1
/******************************************************************
4
* A haskell lexer for the scintilla code control.
5
* Some stuff "lended" from LexPython.cxx and LexCPP.cxx.
6
* External lexer stuff inspired from the caml external lexer.
8
* Written by Tobias Engvall - tumm at dtek dot chalmers dot se
12
* * Implement a folder :)
13
* * Nice Character-lexing (stuff inside '\''), LexPython has
17
*****************************************************************/
28
#include "PropSetSimple.h"
30
#include "StyleContext.h"
32
#include "Scintilla.h"
36
using namespace Scintilla;
39
#ifdef BUILD_AS_EXTERNAL_LEXER
41
#include "ExternalLexer.h"
42
#include "WindowAccessor.h"
44
#define BUILD_EXTERNAL_LEXER 0
48
// Max level of nested comments
49
#define SCE_HA_COMMENTMAX SCE_HA_COMMENTBLOCK3
52
enum kwType { kwOther, kwClass, kwData, kwInstance, kwImport, kwModule, kwType};
54
static inline bool IsNewline(const int ch) {
55
return (ch == '\n' || ch == '\r');
58
static inline bool IsWhitespace(const int ch) {
64
static inline bool IsAWordStart(const int ch) {
65
return (ch < 0x80) && (isalnum(ch) || ch == '_');
68
static inline bool IsAWordChar(const int ch) {
69
return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '\'');
72
static void ColorizeHaskellDoc(unsigned int startPos, int length, int initStyle,
73
WordList *keywordlists[], Accessor &styler) {
75
WordList &keywords = *keywordlists[0];
79
StyleContext sc(startPos, length, initStyle, styler);
81
for (; sc.More(); sc.Forward()) {
83
// Check for state end
85
if (sc.state == SCE_HA_OPERATOR) {
87
sc.SetState(SCE_HA_DEFAULT);
90
else if (sc.state == SCE_HA_STRING) {
92
sc.ForwardSetState(SCE_HA_DEFAULT);
93
} else if (sc.ch == '\\') {
98
else if (sc.state == SCE_HA_CHARACTER) {
100
sc.ForwardSetState(SCE_HA_DEFAULT);
101
} else if (sc.ch == '\\') {
106
else if (sc.state == SCE_HA_NUMBER) {
107
if (!IsADigit(sc.ch)) {
108
sc.SetState(SCE_HA_DEFAULT);
111
// Types, constructors, etc.
112
else if (sc.state == SCE_HA_CAPITAL) {
113
if (!IsAWordChar(sc.ch) || sc.ch == '.') {
114
sc.SetState(SCE_HA_DEFAULT);
118
else if (sc.state == SCE_HA_IDENTIFIER) {
119
if (!IsAWordChar(sc.ch)) {
121
sc.GetCurrent(s, sizeof(s));
122
int style = SCE_HA_IDENTIFIER;
123
if ((kwLast == kwImport) || (strcmp(s,"qualified") == 0) || (strcmp(s,"as") == 0)) {
124
style = SCE_HA_IMPORT;
125
} else if (keywords.InList(s)) {
126
style = SCE_HA_KEYWORD;
127
} else if (kwLast == kwData) {
129
} else if (kwLast == kwClass) {
130
style = SCE_HA_CLASS;
131
} else if (kwLast == kwModule) {
132
style = SCE_HA_MODULE;
133
} else if (isupper(s[0])) {
134
style = SCE_HA_CAPITAL;
136
sc.ChangeState(style);
137
sc.SetState(SCE_HA_DEFAULT);
138
if (style == SCE_HA_KEYWORD) {
139
if (0 == strcmp(s, "class"))
141
else if (0 == strcmp(s, "data"))
143
else if (0 == strcmp(s, "instance"))
145
else if (0 == strcmp(s, "import"))
147
else if (0 == strcmp(s, "module"))
151
} else if (style == SCE_HA_CLASS || style == SCE_HA_IMPORT ||
152
style == SCE_HA_MODULE || style == SCE_HA_CAPITAL ||
153
style == SCE_HA_DATA || style == SCE_HA_INSTANCE) {
160
else if (sc.state == SCE_HA_COMMENTLINE) {
161
if (IsNewline(sc.ch))
162
sc.SetState(SCE_HA_DEFAULT);
165
else if (sc.state >= SCE_HA_COMMENTBLOCK) {
166
if (sc.Match("{-")) {
167
if (sc.state < SCE_HA_COMMENTMAX)
168
sc.SetState(sc.state + 1);
170
else if (sc.Match("-}")) {
172
if (sc.state == SCE_HA_COMMENTBLOCK)
173
sc.ForwardSetState(SCE_HA_DEFAULT);
175
sc.ForwardSetState(sc.state - 1);
179
if (sc.state == SCE_HA_DEFAULT) {
181
if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
182
sc.SetState(SCE_HA_NUMBER);
183
if (sc.ch == '0' && (sc.chNext == 'X' || sc.chNext == 'x')) { // Match anything starting with "0x" or "0X", too
188
else if (sc.Match("--")) {
189
sc.SetState(SCE_HA_COMMENTLINE);
192
else if (sc.Match("{-")) {
193
sc.SetState(SCE_HA_COMMENTBLOCK);
196
else if (sc.Match('\"')) {
197
sc.SetState(SCE_HA_STRING);
200
else if (sc.Match('\'')) {
201
sc.SetState(SCE_HA_CHARACTER);
204
else if (sc.Match('\"')) {
205
sc.SetState(SCE_HA_STRING);
208
else if (isascii(sc.ch) && isoperator(static_cast<char>(sc.ch))) {
209
sc.SetState(SCE_HA_OPERATOR);
212
else if (IsAWordStart(sc.ch)) {
213
sc.SetState(SCE_HA_IDENTIFIER);
221
// External stuff - used for dynamic-loading, not implemented in wxStyledTextCtrl yet.
222
// Inspired by the caml external lexer - Credits to Robert Roessler - http://www.rftp.com
223
#ifdef BUILD_EXTERNAL_LEXER
224
static const char* LexerName = "haskell";
226
void EXT_LEXER_DECL Lex(unsigned int lexer, unsigned int startPos, int length, int initStyle,
227
char *words[], WindowID window, char *props)
230
ps.SetMultiple(props);
231
WindowAccessor wa(window, ps);
234
for (; words[nWL]; nWL++) ;
235
WordList** wl = new WordList* [nWL + 1];
239
wl[i] = new WordList();
240
wl[i]->Set(words[i]);
244
ColorizeHaskellDoc(startPos, length, initStyle, wl, wa);
246
for (i=nWL-1;i>=0;i--)
251
void EXT_LEXER_DECL Fold (unsigned int lexer, unsigned int startPos, int length, int initStyle,
252
char *words[], WindowID window, char *props)
257
int EXT_LEXER_DECL GetLexerCount()
262
void EXT_LEXER_DECL GetLexerName(unsigned int Index, char *name, int buflength)
266
int n = strlen(LexerName);
269
memcpy(name, LexerName, n), name[n] = '\0';
274
LexerModule lmHaskell(SCLEX_HASKELL, ColorizeHaskellDoc, "haskell");