327 lines
9.1 KiB
C++
327 lines
9.1 KiB
C++
|
// Scintilla source code edit control
|
||
|
/** @file LexSmalltalk.cxx
|
||
|
** Lexer for Smalltalk language.
|
||
|
** Written by Sergey Philippov, sphilippov-at-gmail-dot-com
|
||
|
**/
|
||
|
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
|
||
|
// The License.txt file describes the conditions under which this software may be distributed.
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <assert.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#include "ILexer.h"
|
||
|
#include "Scintilla.h"
|
||
|
#include "SciLexer.h"
|
||
|
|
||
|
#include "WordList.h"
|
||
|
#include "LexAccessor.h"
|
||
|
#include "Accessor.h"
|
||
|
#include "StyleContext.h"
|
||
|
#include "CharacterSet.h"
|
||
|
#include "LexerModule.h"
|
||
|
|
||
|
#ifdef SCI_NAMESPACE
|
||
|
using namespace Scintilla;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
| lexTable classificationBlock charClasses |
|
||
|
charClasses := #(#DecDigit #Letter #Special #Upper #BinSel).
|
||
|
lexTable := ByteArray new: 128.
|
||
|
classificationBlock := [ :charClass :chars |
|
||
|
| flag |
|
||
|
flag := 1 bitShift: (charClasses indexOf: charClass) - 1.
|
||
|
chars do: [ :char | lexTable at: char codePoint + 1 put: ((lexTable at: char codePoint + 1) bitOr: flag)]].
|
||
|
|
||
|
classificationBlock
|
||
|
value: #DecDigit value: '0123456789';
|
||
|
value: #Letter value: '_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||
|
value: #Special value: '()[]{};.^:';
|
||
|
value: #BinSel value: '~@%&*-+=|\/,<>?!';
|
||
|
value: #Upper value: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
|
||
|
|
||
|
((String new: 500) streamContents: [ :stream |
|
||
|
stream crLf; nextPutAll: 'static int ClassificationTable[256] = {'.
|
||
|
lexTable keysAndValuesDo: [ :index :value |
|
||
|
((index - 1) rem: 16) == 0 ifTrue: [
|
||
|
stream crLf; tab]
|
||
|
ifFalse: [
|
||
|
stream space].
|
||
|
stream print: value.
|
||
|
index ~= 256 ifTrue: [
|
||
|
stream nextPut: $,]].
|
||
|
stream crLf; nextPutAll: '};'; crLf.
|
||
|
|
||
|
charClasses keysAndValuesDo: [ :index :name |
|
||
|
stream
|
||
|
crLf;
|
||
|
nextPutAll: (
|
||
|
('static inline bool is<1s>(int ch) {return (ch > 0) && (ch %< 0x80) && ((ClassificationTable[ch] & <2p>) != 0);}')
|
||
|
expandMacrosWith: name with: (1 bitShift: (index - 1)))
|
||
|
]]) edit
|
||
|
*/
|
||
|
|
||
|
// autogenerated {{{{
|
||
|
|
||
|
static int ClassificationTable[256] = {
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 16, 0, 0, 0, 16, 16, 0, 4, 4, 16, 16, 16, 16, 4, 16,
|
||
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 16, 16, 16, 16,
|
||
|
16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
|
||
|
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 16, 4, 4, 2,
|
||
|
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 16, 4, 16, 0,
|
||
|
};
|
||
|
|
||
|
static inline bool isDecDigit(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 1) != 0);}
|
||
|
static inline bool isLetter(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 2) != 0);}
|
||
|
static inline bool isSpecial(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 4) != 0);}
|
||
|
static inline bool isUpper(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 8) != 0);}
|
||
|
static inline bool isBinSel(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 16) != 0);}
|
||
|
// autogenerated }}}}
|
||
|
|
||
|
static inline bool isAlphaNumeric(int ch) {
|
||
|
return isDecDigit(ch) || isLetter(ch);
|
||
|
}
|
||
|
|
||
|
static inline bool isDigitOfRadix(int ch, int radix)
|
||
|
{
|
||
|
if (isDecDigit(ch))
|
||
|
return (ch - '0') < radix;
|
||
|
else if (!isUpper(ch))
|
||
|
return false;
|
||
|
else
|
||
|
return (ch - 'A' + 10) < radix;
|
||
|
}
|
||
|
|
||
|
static inline void skipComment(StyleContext& sc)
|
||
|
{
|
||
|
while (sc.More() && sc.ch != '\"')
|
||
|
sc.Forward();
|
||
|
}
|
||
|
|
||
|
static inline void skipString(StyleContext& sc)
|
||
|
{
|
||
|
while (sc.More()) {
|
||
|
if (sc.ch == '\'') {
|
||
|
if (sc.chNext != '\'')
|
||
|
return;
|
||
|
sc.Forward();
|
||
|
}
|
||
|
sc.Forward();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void handleHash(StyleContext& sc)
|
||
|
{
|
||
|
if (isSpecial(sc.chNext)) {
|
||
|
sc.SetState(SCE_ST_SPECIAL);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sc.SetState(SCE_ST_SYMBOL);
|
||
|
sc.Forward();
|
||
|
if (sc.ch == '\'') {
|
||
|
sc.Forward();
|
||
|
skipString(sc);
|
||
|
}
|
||
|
else {
|
||
|
if (isLetter(sc.ch)) {
|
||
|
while (isAlphaNumeric(sc.chNext) || sc.chNext == ':')
|
||
|
sc.Forward();
|
||
|
}
|
||
|
else if (isBinSel(sc.ch)) {
|
||
|
while (isBinSel(sc.chNext))
|
||
|
sc.Forward();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void handleSpecial(StyleContext& sc)
|
||
|
{
|
||
|
if (sc.ch == ':' && sc.chNext == '=') {
|
||
|
sc.SetState(SCE_ST_ASSIGN);
|
||
|
sc.Forward();
|
||
|
}
|
||
|
else {
|
||
|
if (sc.ch == '^')
|
||
|
sc.SetState(SCE_ST_RETURN);
|
||
|
else
|
||
|
sc.SetState(SCE_ST_SPECIAL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void skipInt(StyleContext& sc, int radix)
|
||
|
{
|
||
|
while (isDigitOfRadix(sc.chNext, radix))
|
||
|
sc.Forward();
|
||
|
}
|
||
|
|
||
|
static void handleNumeric(StyleContext& sc)
|
||
|
{
|
||
|
char num[256];
|
||
|
int nl;
|
||
|
int radix;
|
||
|
|
||
|
sc.SetState(SCE_ST_NUMBER);
|
||
|
num[0] = static_cast<char>(sc.ch);
|
||
|
nl = 1;
|
||
|
while (isDecDigit(sc.chNext)) {
|
||
|
num[nl++] = static_cast<char>(sc.chNext);
|
||
|
sc.Forward();
|
||
|
if (nl+1 == sizeof(num)/sizeof(num[0])) // overrun check
|
||
|
break;
|
||
|
}
|
||
|
if (sc.chNext == 'r') {
|
||
|
num[nl] = 0;
|
||
|
if (num[0] == '-')
|
||
|
radix = atoi(num + 1);
|
||
|
else
|
||
|
radix = atoi(num);
|
||
|
sc.Forward();
|
||
|
if (sc.chNext == '-')
|
||
|
sc.Forward();
|
||
|
skipInt(sc, radix);
|
||
|
}
|
||
|
else
|
||
|
radix = 10;
|
||
|
if (sc.chNext != '.' || !isDigitOfRadix(sc.GetRelative(2), radix))
|
||
|
return;
|
||
|
sc.Forward();
|
||
|
skipInt(sc, radix);
|
||
|
if (sc.chNext == 's') {
|
||
|
// ScaledDecimal
|
||
|
sc.Forward();
|
||
|
while (isDecDigit(sc.chNext))
|
||
|
sc.Forward();
|
||
|
return;
|
||
|
}
|
||
|
else if (sc.chNext != 'e' && sc.chNext != 'd' && sc.chNext != 'q')
|
||
|
return;
|
||
|
sc.Forward();
|
||
|
if (sc.chNext == '+' || sc.chNext == '-')
|
||
|
sc.Forward();
|
||
|
skipInt(sc, radix);
|
||
|
}
|
||
|
|
||
|
static inline void handleBinSel(StyleContext& sc)
|
||
|
{
|
||
|
sc.SetState(SCE_ST_BINARY);
|
||
|
while (isBinSel(sc.chNext))
|
||
|
sc.Forward();
|
||
|
}
|
||
|
|
||
|
static void handleLetter(StyleContext& sc, WordList* specialSelectorList)
|
||
|
{
|
||
|
char ident[256];
|
||
|
int il;
|
||
|
int state;
|
||
|
bool doubleColonPresent;
|
||
|
|
||
|
sc.SetState(SCE_ST_DEFAULT);
|
||
|
|
||
|
ident[0] = static_cast<char>(sc.ch);
|
||
|
il = 1;
|
||
|
while (isAlphaNumeric(sc.chNext)) {
|
||
|
ident[il++] = static_cast<char>(sc.chNext);
|
||
|
sc.Forward();
|
||
|
if (il+2 == sizeof(ident)/sizeof(ident[0])) // overrun check
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (sc.chNext == ':') {
|
||
|
doubleColonPresent = true;
|
||
|
ident[il++] = ':';
|
||
|
sc.Forward();
|
||
|
}
|
||
|
else
|
||
|
doubleColonPresent = false;
|
||
|
ident[il] = 0;
|
||
|
|
||
|
if (specialSelectorList->InList(ident))
|
||
|
state = SCE_ST_SPEC_SEL;
|
||
|
else if (doubleColonPresent)
|
||
|
state = SCE_ST_KWSEND;
|
||
|
else if (isUpper(ident[0]))
|
||
|
state = SCE_ST_GLOBAL;
|
||
|
else {
|
||
|
if (!strcmp(ident, "self"))
|
||
|
state = SCE_ST_SELF;
|
||
|
else if (!strcmp(ident, "super"))
|
||
|
state = SCE_ST_SUPER;
|
||
|
else if (!strcmp(ident, "nil"))
|
||
|
state = SCE_ST_NIL;
|
||
|
else if (!strcmp(ident, "true") || !strcmp(ident, "false"))
|
||
|
state = SCE_ST_BOOL;
|
||
|
else
|
||
|
state = SCE_ST_DEFAULT;
|
||
|
}
|
||
|
|
||
|
sc.ChangeState(state);
|
||
|
}
|
||
|
|
||
|
static void colorizeSmalltalkDoc(unsigned int startPos, int length, int initStyle, WordList *wordLists[], Accessor &styler)
|
||
|
{
|
||
|
StyleContext sc(startPos, length, initStyle, styler);
|
||
|
|
||
|
if (initStyle == SCE_ST_COMMENT) {
|
||
|
skipComment(sc);
|
||
|
if (sc.More())
|
||
|
sc.Forward();
|
||
|
}
|
||
|
else if (initStyle == SCE_ST_STRING) {
|
||
|
skipString(sc);
|
||
|
if (sc.More())
|
||
|
sc.Forward();
|
||
|
}
|
||
|
|
||
|
for (; sc.More(); sc.Forward()) {
|
||
|
int ch;
|
||
|
|
||
|
ch = sc.ch;
|
||
|
if (ch == '\"') {
|
||
|
sc.SetState(SCE_ST_COMMENT);
|
||
|
sc.Forward();
|
||
|
skipComment(sc);
|
||
|
}
|
||
|
else if (ch == '\'') {
|
||
|
sc.SetState(SCE_ST_STRING);
|
||
|
sc.Forward();
|
||
|
skipString(sc);
|
||
|
}
|
||
|
else if (ch == '#')
|
||
|
handleHash(sc);
|
||
|
else if (ch == '$') {
|
||
|
sc.SetState(SCE_ST_CHARACTER);
|
||
|
sc.Forward();
|
||
|
}
|
||
|
else if (isSpecial(ch))
|
||
|
handleSpecial(sc);
|
||
|
else if (isDecDigit(ch))
|
||
|
handleNumeric(sc);
|
||
|
else if (isLetter(ch))
|
||
|
handleLetter(sc, wordLists[0]);
|
||
|
else if (isBinSel(ch)) {
|
||
|
if (ch == '-' && isDecDigit(sc.chNext))
|
||
|
handleNumeric(sc);
|
||
|
else
|
||
|
handleBinSel(sc);
|
||
|
}
|
||
|
else
|
||
|
sc.SetState(SCE_ST_DEFAULT);
|
||
|
}
|
||
|
sc.Complete();
|
||
|
}
|
||
|
|
||
|
static const char* const smalltalkWordListDesc[] = {
|
||
|
"Special selectors",
|
||
|
0
|
||
|
};
|
||
|
|
||
|
LexerModule lmSmalltalk(SCLEX_SMALLTALK, colorizeSmalltalkDoc, "smalltalk", NULL, smalltalkWordListDesc);
|