1// Scintilla source code edit control
2/** @file LexMaxima.cxx
3 ** Lexer for Maxima (http://maxima.sourceforge.net).
4 ** Written by Gunter Königsmann based on the lisp lexer by Alexey Yutkin and Neil Hodgson .
5 **/
6// Copyright 2018 by Gunter Königsmann <wxMaxima@physikbuch.de>
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 <string>
17#include <string_view>
18
19#include "ILexer.h"
20#include "Scintilla.h"
21#include "SciLexer.h"
22
23#include "WordList.h"
24#include "LexAccessor.h"
25#include "Accessor.h"
26#include "StyleContext.h"
27#include "CharacterSet.h"
28#include "LexerModule.h"
29using namespace Lexilla;
30
31static inline bool isMaximaoperator(char ch) {
32 return (ch == '\'' || ch == '`' || ch == '(' ||
33 ch == ')' || ch == '[' || ch == ']' ||
34 ch == '{' || ch == '}' || ch == '!' ||
35 ch == '*' || ch == '/' || ch == '^' ||
36 ch == ',' || ch == ':' || ch == '+' ||
37 ch == '-');
38}
39
40static void ColouriseMaximaDoc(Sci_PositionU startPos, Sci_Position length, int lastStyle,
41 WordList *[],
42 Accessor &styler) {
43
44 styler.StartAt(startPos);
45
46 Sci_PositionU lengthDoc = startPos + length;
47 styler.StartSegment(startPos);
48
49 Sci_PositionU i = startPos;
50
51 // If we are in the middle of a comment we go back to its start before highlighting
52 if(lastStyle == SCE_MAXIMA_COMMENT)
53 {
54 while((i>0) &&
55 !((styler.SafeGetCharAt(i+1) == '*') && (styler.SafeGetCharAt(i) == '/')))
56 i--;
57 }
58
59 for (; i < lengthDoc; i++) {
60 char ch = styler.SafeGetCharAt(i);
61 char chNext = styler.SafeGetCharAt(i + 1);
62
63 if (styler.IsLeadByte(ch))
64 continue;
65
66 // Handle comments.
67 // Comments start with /* and end with */
68 if((ch == '/') && (chNext == '*'))
69 {
70 i++;i++;
71
72 chNext = styler.SafeGetCharAt(i);
73 for (; i < lengthDoc; i++)
74 {
75 ch = chNext;
76 chNext = styler.SafeGetCharAt(i + 1);
77 if((ch == '*') && (chNext == '/'))
78 {
79 i++;
80 i++;
81 break;
82 }
83 }
84 if(i > lengthDoc)
85 i = lengthDoc;
86 i--;
87 styler.ColourTo(i, SCE_MAXIMA_COMMENT);
88 continue;
89 }
90
91 // Handle Operators
92 if(isMaximaoperator(ch))
93 {
94 styler.ColourTo(i, SCE_MAXIMA_OPERATOR);
95 continue;
96 }
97
98 // Handle command endings.
99 if((ch == '$') || (ch == ';'))
100 {
101 styler.ColourTo(i, SCE_MAXIMA_COMMANDENDING);
102 continue;
103 }
104
105 // Handle numbers. Numbers always begin with a digit.
106 if(IsASCII(ch) && isdigit(ch))
107 {
108 i++;
109 for (; i < lengthDoc; i++)
110 {
111 ch = chNext;
112 chNext = styler.SafeGetCharAt(i + 1);
113
114 if(ch == '.')
115 continue;
116
117 // A "e" or similar can be followed by a "+" or a "-"
118 if(((ch == 'e') || (ch == 'b') || (ch == 'g') || (ch == 'f')) &&
119 ((chNext == '+') || (chNext == '-')))
120 {
121 i++;
122 chNext = styler.SafeGetCharAt(i + 1);
123 continue;
124 }
125
126 if(!IsASCII(ch) || !(isdigit(ch) || islower(ch) || isupper(ch)))
127 {
128 i--;
129 break;
130 }
131 }
132 styler.ColourTo(i, SCE_MAXIMA_NUMBER);
133 continue;
134 }
135
136 // Handle strings
137 if(ch == '\"')
138 {
139 i++;
140 for (; i < lengthDoc; i++)
141 {
142 ch = chNext;
143 chNext = styler.SafeGetCharAt(i + 1);
144 if(ch == '\\')
145 i++;
146 else
147 {
148 if(ch == '\"')
149 break;
150 }
151 }
152 styler.ColourTo(i, SCE_MAXIMA_STRING);
153 continue;
154 }
155
156 // Handle keywords. Maxima treats Non-ASCII chars as ordinary letters.
157 if(((!IsASCII(ch))) || isalpha(ch) || (ch == '_'))
158 {
159 char cmd[100];
160 int cmdidx = 0;
161 memset(cmd,0,100);
162 cmd[cmdidx++] = ch;
163 i++;
164 for (; i < lengthDoc; i++)
165 {
166 ch = chNext;
167 chNext = styler.SafeGetCharAt(i + 1);
168 if(ch == '\\')
169 {
170 if(cmdidx < 99)
171 cmd[cmdidx++] = ch;
172 i++;
173 if(cmdidx < 99)
174 cmd[cmdidx++] = ch;
175 continue;
176 }
177 if(isMaximaoperator(ch) || ((IsASCII(ch) && !isalpha(ch) && !isdigit(ch) && (ch != '_'))))
178 {
179 i--;
180 break;
181 }
182 if(cmdidx < 99)
183 cmd[cmdidx++] = ch;
184 }
185
186 // A few known keywords
187 if(
188 (strncmp(cmd,"if",99) == 0) ||
189 (strncmp(cmd,"then",99) == 0) ||
190 (strncmp(cmd,"else",99) == 0) ||
191 (strncmp(cmd,"thru",99) == 0) ||
192 (strncmp(cmd,"for",99) == 0) ||
193 (strncmp(cmd,"while",99) == 0) ||
194 (strncmp(cmd,"do",99) == 0)
195 )
196 {
197 styler.ColourTo(i, SCE_MAXIMA_COMMAND);
198 continue;
199 }
200
201 // All other keywords are functions if they are followed
202 // by an opening parenthesis
203 char nextNonwhitespace = ' ';
204 for (Sci_PositionU o = i + 1; o < lengthDoc; o++)
205 {
206 nextNonwhitespace = styler.SafeGetCharAt(o);
207 if(!IsASCII(nextNonwhitespace) || !isspacechar(nextNonwhitespace))
208 break;
209 }
210 if(nextNonwhitespace == '(')
211 {
212 styler.ColourTo(i, SCE_MAXIMA_COMMAND);
213 }
214 else
215 {
216 styler.ColourTo(i, SCE_MAXIMA_VARIABLE);
217 }
218 continue;
219 }
220
221 styler.ColourTo(i-1, SCE_MAXIMA_UNKNOWN);
222 }
223}
224
225LexerModule lmMaxima(SCLEX_MAXIMA, ColouriseMaximaDoc, "maxima", 0, 0);
226