1// Scintilla source code edit control
2/** @file LexSML.cxx
3 ** Lexer for SML.
4 **/
5// Copyright 2009 by James Moffatt and Yuzhou Xin
6// Modified from LexCaml.cxx by Robert Roessler <robertr@rftp.com> Copyright 2005
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"
29
30#if defined(__clang__)
31#pragma clang diagnostic ignored "-Wcomma"
32#endif
33
34inline int issml(int c) {return isalnum(c) || c == '_';}
35inline int issmlf(int c) {return isalpha(c) || c == '_';}
36inline int issmld(int c) {return isdigit(c) || c == '_';}
37
38
39using namespace Lexilla;
40
41static void ColouriseSMLDoc(
42 Sci_PositionU startPos, Sci_Position length,
43 int initStyle,
44 WordList *keywordlists[],
45 Accessor &styler)
46{
47 StyleContext sc(startPos, length, initStyle, styler);
48 int nesting = 0;
49 if (sc.state < SCE_SML_STRING)
50 sc.state = SCE_SML_DEFAULT;
51 if (sc.state >= SCE_SML_COMMENT)
52 nesting = (sc.state & 0x0f) - SCE_SML_COMMENT;
53
54 Sci_PositionU chToken = 0;
55 int chBase = 0, chLit = 0;
56 WordList& keywords = *keywordlists[0];
57 WordList& keywords2 = *keywordlists[1];
58 WordList& keywords3 = *keywordlists[2];
59 const int useMagic = styler.GetPropertyInt("lexer.caml.magic", 0);
60
61 while (sc.More()) {
62 int state2 = -1;
63 Sci_Position chColor = sc.currentPos - 1;
64 bool advance = true;
65
66 switch (sc.state & 0x0f) {
67 case SCE_SML_DEFAULT:
68 chToken = sc.currentPos;
69 if (issmlf(sc.ch))
70 state2 = SCE_SML_IDENTIFIER;
71 else if (sc.Match('`') && issmlf(sc.chNext))
72 state2 = SCE_SML_TAGNAME;
73 else if (sc.Match('#')&&isdigit(sc.chNext))
74 state2 = SCE_SML_LINENUM;
75 else if (sc.Match('#','\"')){
76 state2 = SCE_SML_CHAR,chLit = 0;
77 sc.Forward();
78
79 }
80 else if (isdigit(sc.ch)) {
81 state2 = SCE_SML_NUMBER, chBase = 10;
82 if (sc.Match('0') && strchr("xX", sc.chNext))
83 chBase = 16, sc.Forward();}
84 else if (sc.Match('\"')&&sc.chPrev!='#')
85 state2 = SCE_SML_STRING;
86 else if (sc.Match('(', '*')){
87 state2 = SCE_SML_COMMENT,
88 sc.ch = ' ',
89 sc.Forward();}
90 else if (strchr("!~"
91 "=<>@^+-*/"
92 "()[];,:.#", sc.ch))
93 state2 = SCE_SML_OPERATOR;
94 break;
95
96 case SCE_SML_IDENTIFIER:
97 if (!(issml(sc.ch) || sc.Match('\''))) {
98 const Sci_Position n = sc.currentPos - chToken;
99 if (n < 24) {
100 char t[24];
101 for (Sci_Position i = -n; i < 0; i++)
102 t[n + i] = static_cast<char>(sc.GetRelative(i));
103 t[n] = '\0';
104 if ((n == 1 && sc.chPrev == '_') || keywords.InList(t))
105 sc.ChangeState(SCE_SML_KEYWORD);
106 else if (keywords2.InList(t))
107 sc.ChangeState(SCE_SML_KEYWORD2);
108 else if (keywords3.InList(t))
109 sc.ChangeState(SCE_SML_KEYWORD3);
110 }
111 state2 = SCE_SML_DEFAULT, advance = false;
112 }
113 break;
114
115 case SCE_SML_TAGNAME:
116 if (!(issml(sc.ch) || sc.Match('\'')))
117 state2 = SCE_SML_DEFAULT, advance = false;
118 break;
119
120 case SCE_SML_LINENUM:
121 if (!isdigit(sc.ch))
122 state2 = SCE_SML_DEFAULT, advance = false;
123 break;
124
125 case SCE_SML_OPERATOR: {
126 const char* o = 0;
127 if (issml(sc.ch) || isspace(sc.ch)
128 || (o = strchr(")]};,\'\"`#", sc.ch),o)
129 || !strchr("!$%&*+-./:<=>?@^|~", sc.ch)) {
130 if (o && strchr(")]};,", sc.ch)) {
131 if ((sc.Match(')') && sc.chPrev == '(')
132 || (sc.Match(']') && sc.chPrev == '['))
133 sc.ChangeState(SCE_SML_KEYWORD);
134 chColor++;
135 } else
136 advance = false;
137 state2 = SCE_SML_DEFAULT;
138 }
139 break;
140 }
141
142 case SCE_SML_NUMBER:
143 if (issmld(sc.ch) || IsADigit(sc.ch, chBase))
144 break;
145 if ((sc.Match('l') || sc.Match('L') || sc.Match('n'))
146 && (issmld(sc.chPrev) || IsADigit(sc.chPrev, chBase)))
147 break;
148 if (chBase == 10) {
149 if (sc.Match('.') && issmld(sc.chPrev))
150 break;
151 if ((sc.Match('e') || sc.Match('E'))
152 && (issmld(sc.chPrev) || sc.chPrev == '.'))
153 break;
154 if ((sc.Match('+') || sc.Match('-'))
155 && (sc.chPrev == 'e' || sc.chPrev == 'E'))
156 break;
157 }
158 state2 = SCE_SML_DEFAULT, advance = false;
159 break;
160
161 case SCE_SML_CHAR:
162 if (sc.Match('\\')) {
163 chLit = 1;
164 if (sc.chPrev == '\\')
165 sc.ch = ' ';
166 } else if ((sc.Match('\"') && sc.chPrev != '\\') || sc.atLineEnd) {
167 state2 = SCE_SML_DEFAULT;
168 chLit = 1;
169 if (sc.Match('\"'))
170 chColor++;
171 else
172 sc.ChangeState(SCE_SML_IDENTIFIER);
173 } else if (chLit < 1 && sc.currentPos - chToken >= 3)
174 sc.ChangeState(SCE_SML_IDENTIFIER), advance = false;
175 break;
176
177 case SCE_SML_STRING:
178 if (sc.Match('\\') && sc.chPrev == '\\')
179 sc.ch = ' ';
180 else if (sc.Match('\"') && sc.chPrev != '\\')
181 state2 = SCE_SML_DEFAULT, chColor++;
182 break;
183
184 case SCE_SML_COMMENT:
185 case SCE_SML_COMMENT1:
186 case SCE_SML_COMMENT2:
187 case SCE_SML_COMMENT3:
188 if (sc.Match('(', '*'))
189 state2 = sc.state + 1, chToken = sc.currentPos,
190 sc.ch = ' ',
191 sc.Forward(), nesting++;
192 else if (sc.Match(')') && sc.chPrev == '*') {
193 if (nesting)
194 state2 = (sc.state & 0x0f) - 1, chToken = 0, nesting--;
195 else
196 state2 = SCE_SML_DEFAULT;
197 chColor++;
198 } else if (useMagic && sc.currentPos - chToken == 4
199 && sc.Match('c') && sc.chPrev == 'r' && sc.GetRelative(-2) == '@')
200 sc.state |= 0x10;
201 break;
202 }
203
204 if (state2 >= 0)
205 styler.ColourTo(chColor, sc.state), sc.ChangeState(state2);
206 if (advance)
207 sc.Forward();
208 }
209
210 sc.Complete();
211}
212
213static void FoldSMLDoc(
214 Sci_PositionU, Sci_Position,
215 int,
216 WordList *[],
217 Accessor &)
218{
219}
220
221static const char * const SMLWordListDesc[] = {
222 "Keywords",
223 "Keywords2",
224 "Keywords3",
225 0
226};
227
228LexerModule lmSML(SCLEX_SML, ColouriseSMLDoc, "SML", FoldSMLDoc, SMLWordListDesc);
229
230