1 // Copyright (c) 1990-2007, Scientific Toolworks, Inc.
2 // Author: Jason Haslam
3 // The License.txt file describes the conditions under which this software may be distributed.
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <assert.h>
10 #include <ctype.h>
11 
12 #include "ILexer.h"
13 #include "Scintilla.h"
14 #include "SciLexer.h"
15 
16 #include "WordList.h"
17 #include "LexAccessor.h"
18 #include "Accessor.h"
19 #include "StyleContext.h"
20 #include "CharacterSet.h"
21 #include "LexerModule.h"
22 
23 using namespace Scintilla;
24 
GetRange(Sci_PositionU start,Sci_PositionU end,Accessor & styler,char * s,Sci_PositionU len)25 static void GetRange(Sci_PositionU start,
26                      Sci_PositionU end,
27                      Accessor &styler,
28                      char *s,
29                      Sci_PositionU len) {
30 	Sci_PositionU i = 0;
31 	while ((i < end - start + 1) && (i < len-1)) {
32 		s[i] = static_cast<char>(tolower(styler[start + i]));
33 		i++;
34 	}
35 	s[i] = '\0';
36 }
37 
ColourisePlmDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * keywordlists[],Accessor & styler)38 static void ColourisePlmDoc(Sci_PositionU startPos,
39                             Sci_Position length,
40                             int initStyle,
41                             WordList *keywordlists[],
42                             Accessor &styler)
43 {
44 	Sci_PositionU endPos = startPos + length;
45 	int state = initStyle;
46 
47 	styler.StartAt(startPos);
48 	styler.StartSegment(startPos);
49 
50 	for (Sci_PositionU i = startPos; i < endPos; i++) {
51 		char ch = styler.SafeGetCharAt(i);
52 		char chNext = styler.SafeGetCharAt(i + 1);
53 
54 		if (state == SCE_PLM_DEFAULT) {
55 			if (ch == '/' && chNext == '*') {
56 				styler.ColourTo(i - 1, state);
57 				state = SCE_PLM_COMMENT;
58 			} else if (ch == '\'') {
59 				styler.ColourTo(i - 1, state);
60 				state = SCE_PLM_STRING;
61 			} else if (isdigit(ch)) {
62 				styler.ColourTo(i - 1, state);
63 				state = SCE_PLM_NUMBER;
64 			} else if (isalpha(ch)) {
65 				styler.ColourTo(i - 1, state);
66 				state = SCE_PLM_IDENTIFIER;
67 			} else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' ||
68 			           ch == '=' || ch == '<' || ch == '>' || ch == ':') {
69 				styler.ColourTo(i - 1, state);
70 				state = SCE_PLM_OPERATOR;
71 			} else if (ch == '$') {
72 				styler.ColourTo(i - 1, state);
73 				state = SCE_PLM_CONTROL;
74 			}
75 		} else if (state == SCE_PLM_COMMENT) {
76 			if (ch == '*' && chNext == '/') {
77 				i++;
78 				styler.ColourTo(i, state);
79 				state = SCE_PLM_DEFAULT;
80 			}
81 		} else if (state == SCE_PLM_STRING) {
82 			if (ch == '\'') {
83 				if (chNext == '\'') {
84 					i++;
85 				} else {
86 					styler.ColourTo(i, state);
87 					state = SCE_PLM_DEFAULT;
88 				}
89 			}
90 		} else if (state == SCE_PLM_NUMBER) {
91 			if (!isdigit(ch) && !isalpha(ch) && ch != '$') {
92 				i--;
93 				styler.ColourTo(i, state);
94 				state = SCE_PLM_DEFAULT;
95 			}
96 		} else if (state == SCE_PLM_IDENTIFIER) {
97 			if (!isdigit(ch) && !isalpha(ch) && ch != '$') {
98 				// Get the entire identifier.
99 				char word[1024];
100 				Sci_Position segmentStart = styler.GetStartSegment();
101 				GetRange(segmentStart, i - 1, styler, word, sizeof(word));
102 
103 				i--;
104 				if (keywordlists[0]->InList(word))
105 					styler.ColourTo(i, SCE_PLM_KEYWORD);
106 				else
107 					styler.ColourTo(i, state);
108 				state = SCE_PLM_DEFAULT;
109 			}
110 		} else if (state == SCE_PLM_OPERATOR) {
111 			if (ch != '=' && ch != '>') {
112 				i--;
113 				styler.ColourTo(i, state);
114 				state = SCE_PLM_DEFAULT;
115 			}
116 		} else if (state == SCE_PLM_CONTROL) {
117 			if (ch == '\r' || ch == '\n') {
118 				styler.ColourTo(i - 1, state);
119 				state = SCE_PLM_DEFAULT;
120 			}
121 		}
122 	}
123 	styler.ColourTo(endPos - 1, state);
124 }
125 
FoldPlmDoc(Sci_PositionU startPos,Sci_Position length,int initStyle,WordList * [],Accessor & styler)126 static void FoldPlmDoc(Sci_PositionU startPos,
127                        Sci_Position length,
128                        int initStyle,
129                        WordList *[],
130                        Accessor &styler)
131 {
132 	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
133 	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
134 	Sci_PositionU endPos = startPos + length;
135 	int visibleChars = 0;
136 	Sci_Position lineCurrent = styler.GetLine(startPos);
137 	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
138 	int levelCurrent = levelPrev;
139 	char chNext = styler[startPos];
140 	int styleNext = styler.StyleAt(startPos);
141 	int style = initStyle;
142 	Sci_Position startKeyword = 0;
143 
144 	for (Sci_PositionU i = startPos; i < endPos; i++) {
145 		char ch = chNext;
146 		chNext = styler.SafeGetCharAt(i + 1);
147 		int stylePrev = style;
148 		style = styleNext;
149 		styleNext = styler.StyleAt(i + 1);
150 		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
151 
152 		if (stylePrev != SCE_PLM_KEYWORD && style == SCE_PLM_KEYWORD)
153 			startKeyword = i;
154 
155 		if (style == SCE_PLM_KEYWORD && styleNext != SCE_PLM_KEYWORD) {
156 			char word[1024];
157 			GetRange(startKeyword, i, styler, word, sizeof(word));
158 
159 			if (strcmp(word, "procedure") == 0 || strcmp(word, "do") == 0)
160 				levelCurrent++;
161 			else if (strcmp(word, "end") == 0)
162 				levelCurrent--;
163 		}
164 
165 		if (foldComment) {
166 			if (stylePrev != SCE_PLM_COMMENT && style == SCE_PLM_COMMENT)
167 				levelCurrent++;
168 			else if (stylePrev == SCE_PLM_COMMENT && style != SCE_PLM_COMMENT)
169 				levelCurrent--;
170 		}
171 
172 		if (atEOL) {
173 			int lev = levelPrev;
174 			if (visibleChars == 0 && foldCompact)
175 				lev |= SC_FOLDLEVELWHITEFLAG;
176 			if ((levelCurrent > levelPrev) && (visibleChars > 0))
177 				lev |= SC_FOLDLEVELHEADERFLAG;
178 			if (lev != styler.LevelAt(lineCurrent)) {
179 				styler.SetLevel(lineCurrent, lev);
180 			}
181 			lineCurrent++;
182 			levelPrev = levelCurrent;
183 			visibleChars = 0;
184 		}
185 
186 		if (!isspacechar(ch))
187 			visibleChars++;
188 	}
189 
190 	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
191 	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
192 }
193 
194 static const char *const plmWordListDesc[] = {
195 	"Keywords",
196 	0
197 };
198 
199 LexerModule lmPLM(SCLEX_PLM, ColourisePlmDoc, "PL/M", FoldPlmDoc, plmWordListDesc);
200