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