1
// Scintilla source code edit control
4
* Lexer for GE(r) Smallworld(tm) MagikSF
6
// Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
7
// The License.txt file describes the conditions under which this software may be distributed.
19
#include "StyleContext.h"
21
#include "Scintilla.h"
25
using namespace Scintilla;
29
* Is it a core character (C isalpha(), exclamation and question mark)
31
* \param ch The character
32
* \return True if ch is a character, False otherwise
34
static inline bool IsAlphaCore(int ch) {
35
return (isalpha(ch) || ch == '!' || ch == '?');
39
* Is it a character (IsAlphaCore() and underscore)
41
* \param ch The character
42
* \return True if ch is a character, False otherwise
44
static inline bool IsAlpha(int ch) {
45
return (IsAlphaCore(ch) || ch == '_');
49
* Is it a symbolic character (IsAlpha() and colon)
51
* \param ch The character
52
* \return True if ch is a character, False otherwise
54
static inline bool IsAlphaSym(int ch) {
55
return (IsAlpha(ch) || ch == ':');
59
* Is it a numerical character (IsAlpha() and 0 - 9)
61
* \param ch The character
62
* \return True if ch is a character, False otherwise
64
static inline bool IsAlNum(int ch) {
65
return ((ch >= '0' && ch <= '9') || IsAlpha(ch));
69
* Is it a symbolic numerical character (IsAlNum() and colon)
71
* \param ch The character
72
* \return True if ch is a character, False otherwise
74
static inline bool IsAlNumSym(int ch) {
75
return (IsAlNum(ch) || ch == ':');
81
* \param startPos Where to start scanning
82
* \param length Where to scan to
83
* \param initStyle The style at the initial point, not used in this folder
84
* \param keywordslists The keywordslists, currently, number 5 is used
85
* \param styler The styler
87
static void ColouriseMagikDoc(unsigned int startPos, int length, int initStyle,
88
WordList *keywordlists[], Accessor &styler) {
89
styler.StartAt(startPos);
91
WordList &keywords = *keywordlists[0];
92
WordList &pragmatics = *keywordlists[1];
93
WordList &containers = *keywordlists[2];
94
WordList &flow = *keywordlists[3];
95
WordList &characters = *keywordlists[4];
97
StyleContext sc(startPos, length, initStyle, styler);
100
for (; sc.More(); sc.Forward()) {
105
if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT);
106
else sc.SetState(SCE_MAGIK_COMMENT);
107
for(; sc.More() && !(sc.atLineEnd); sc.Forward());
108
sc.SetState(SCE_MAGIK_DEFAULT);
113
sc.SetState(SCE_MAGIK_STRING);
118
for(; sc.More() && sc.ch != '"'; sc.Forward());
121
sc.ForwardSetState(SCE_MAGIK_DEFAULT);
126
if(sc.state == SCE_MAGIK_DEFAULT) {
128
// A certain keyword has been detected
129
if (sc.ch == '_' && (
130
sc.currentPos == 0 || !IsAlNum(sc.chPrev))) {
132
memset(keyword, '\0', 50);
135
int scanPosition = 0;
138
char keywordChar = static_cast<char>(
139
tolower(styler.SafeGetCharAt(
141
static_cast<int>(sc.currentPos+1), ' ')));
142
if(IsAlpha(keywordChar)) {
143
keyword[scanPosition] = keywordChar;
150
if(pragmatics.InList(keyword)) {
151
sc.SetState(SCE_MAGIK_PRAGMA);
154
// it is a normal keyword like _local, _self, etc.
155
else if(keywords.InList(keyword)) {
156
sc.SetState(SCE_MAGIK_KEYWORD);
159
// It is a container keyword, such as _method, _proc, etc.
160
else if(containers.InList(keyword)) {
161
sc.SetState(SCE_MAGIK_CONTAINER);
164
// It is a flow keyword, such as _for, _if, _try, etc.
165
else if(flow.InList(keyword)) {
166
sc.SetState(SCE_MAGIK_FLOW);
169
// Interpret as unknown keyword
171
sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD);
175
// Symbolic expression
176
else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) {
177
sc.SetState(SCE_MAGIK_SYMBOL);
178
bool firstTrip = true;
179
for(sc.Forward(); sc.More(); sc.Forward()) {
180
if(firstTrip && IsAlphaSym(sc.ch));
181
else if(!firstTrip && IsAlNumSym(sc.ch));
182
else if(sc.ch == '|') {
184
sc.More() && sc.ch != '|';
191
sc.SetState(SCE_MAGIK_DEFAULT);
195
// Identifier (label) expression
196
else if(sc.ch == '@') {
197
sc.SetState(SCE_MAGIK_IDENTIFIER);
198
bool firstTrip = true;
199
for(sc.Forward(); sc.More(); sc.Forward()) {
200
if(firstTrip && IsAlphaCore(sc.ch)) {
203
else if(!firstTrip && IsAlpha(sc.ch));
206
sc.SetState(SCE_MAGIK_DEFAULT);
210
// Start of a character
211
else if(sc.ch == '%') {
212
sc.SetState(SCE_MAGIK_CHARACTER);
215
memset(keyword, '\0', 50);
218
int scanPosition = 0;
221
char keywordChar = static_cast<char>(
222
tolower(styler.SafeGetCharAt(
224
static_cast<int>(sc.currentPos), ' ')));
225
if(IsAlpha(keywordChar)) {
226
keyword[scanPosition] = keywordChar;
232
if(characters.InList(keyword)) {
233
sc.Forward(strlen(keyword));
238
sc.SetState(SCE_MAGIK_DEFAULT);
255
sc.SetState(SCE_MAGIK_OPERATOR);
259
else if(sc.ch == '(' || sc.ch == ')') {
260
sc.SetState(SCE_MAGIK_BRACE_BLOCK);
264
else if(sc.ch == '{' || sc.ch == '}') {
265
sc.SetState(SCE_MAGIK_BRACKET_BLOCK);
269
else if(sc.ch == '[' || sc.ch == ']') {
270
sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK);
278
sc.state == SCE_MAGIK_OPERATOR ||
279
sc.state == SCE_MAGIK_BRACE_BLOCK ||
280
sc.state == SCE_MAGIK_BRACKET_BLOCK ||
281
sc.state == SCE_MAGIK_SQBRACKET_BLOCK) {
282
sc.SetState(SCE_MAGIK_DEFAULT);
286
// It is the pragma state
287
else if(sc.state == SCE_MAGIK_PRAGMA) {
288
if(!IsAlpha(sc.ch)) {
289
sc.SetState(SCE_MAGIK_DEFAULT);
294
// It is the keyword state
296
sc.state == SCE_MAGIK_KEYWORD ||
297
sc.state == SCE_MAGIK_CONTAINER ||
298
sc.state == SCE_MAGIK_FLOW ||
299
sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) {
300
if(!IsAlpha(sc.ch)) {
301
sc.SetState(SCE_MAGIK_DEFAULT);
311
* The word list description
313
static const char * const magikWordListDesc[] = {
314
"Accessors (local, global, self, super, thisthread)",
315
"Pragmatic (pragma, private)",
316
"Containers (method, block, proc)",
317
"Flow (if, then, elif, else)",
318
"Characters (space, tab, newline, return)",
319
"Fold Containers (method, proc, block, if, loop)",
323
* This function detects keywords which are able to have a body. Note that it
324
* uses the Fold Containers word description, not the containers description. It
325
* only works when the style at that particular position is set on Containers
326
* or Flow (number 3 or 4).
328
* \param keywordslist The list of keywords that are scanned, they should only
329
* contain the start keywords, not the end keywords
330
* \param The actual keyword
331
* \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword
334
static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) {
336
strlen(keyword) > 3 &&
337
keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') {
338
if (keywordslist.InList(keyword + 3)) {
343
if(keywordslist.InList(keyword)) {
352
* The folding function
354
* \param startPos Where to start scanning
355
* \param length Where to scan to
356
* \param keywordslists The keywordslists, currently, number 5 is used
357
* \param styler The styler
359
static void FoldMagikDoc(unsigned int startPos, int length, int,
360
WordList *keywordslists[], Accessor &styler) {
362
bool compact = styler.GetPropertyInt("fold.compact") != 0;
364
WordList &foldingElements = *keywordslists[5];
365
int endPos = startPos + length;
366
int line = styler.GetLine(startPos);
367
int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;
368
int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
371
int currentPos = startPos;
374
char currentState = styler.StyleAt(currentPos);
375
char c = styler.SafeGetCharAt(currentPos, ' ');
376
int prevLine = styler.GetLine(currentPos - 1);
377
line = styler.GetLine(currentPos);
380
if(prevLine < line) {
381
styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG);
382
flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
387
currentState == SCE_MAGIK_CONTAINER ||
388
currentState == SCE_MAGIK_FLOW
393
memset(keyword, '\0', 50);
396
int scanPosition = 0;
399
char keywordChar = static_cast<char>(
400
tolower(styler.SafeGetCharAt(
402
currentPos + 1, ' ')));
403
if(IsAlpha(keywordChar)) {
404
keyword[scanPosition] = keywordChar;
410
if(IsFoldingContainer(foldingElements, keyword) > 0) {
413
styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
415
} else if(IsFoldingContainer(foldingElements, keyword) < 0) {
416
styler.SetLevel(line, styler.LevelAt(line));
423
currentState == SCE_MAGIK_BRACE_BLOCK ||
424
currentState == SCE_MAGIK_BRACKET_BLOCK ||
425
currentState == SCE_MAGIK_SQBRACKET_BLOCK)) {
426
if(c == '{' || c == '[' || c == '(') {
429
styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
431
} else if(c == '}' || c == ']' || c == ')') {
432
styler.SetLevel(line, styler.LevelAt(line));
441
* Injecting the module
443
LexerModule lmMagikSF(
444
SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc);