diff options
Diffstat (limited to 'src/LexMSSQL.cpp')
-rwxr-xr-x | src/LexMSSQL.cpp | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/src/LexMSSQL.cpp b/src/LexMSSQL.cpp new file mode 100755 index 0000000..a946668 --- /dev/null +++ b/src/LexMSSQL.cpp @@ -0,0 +1,359 @@ +// Scintilla source code edit control +/** @file LexMSSQL.cxx + ** Lexer for MSSQL. + **/ +// By Filip Yaghob <fyaghob@gmail.com> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#define KW_MSSQL_STATEMENTS 0 +#define KW_MSSQL_DATA_TYPES 1 +#define KW_MSSQL_SYSTEM_TABLES 2 +#define KW_MSSQL_GLOBAL_VARIABLES 3 +#define KW_MSSQL_FUNCTIONS 4 +#define KW_MSSQL_STORED_PROCEDURES 5 +#define KW_MSSQL_OPERATORS 6 + +static bool isMSSQLOperator(char ch) { + if (isascii(ch) && isalnum(ch)) + return false; + // '.' left out as it is used to make up numbers + if (ch == '%' || ch == '^' || ch == '&' || ch == '*' || + ch == '-' || ch == '+' || ch == '=' || ch == '|' || + ch == '<' || ch == '>' || ch == '/' || + ch == '!' || ch == '~' || ch == '(' || ch == ')' || + ch == ',') + return true; + return false; +} + +static char classifyWordSQL(unsigned int start, + unsigned int end, + WordList *keywordlists[], + Accessor &styler, + unsigned int actualState, + unsigned int prevState) { + char s[256]; + bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.'); + + WordList &kwStatements = *keywordlists[KW_MSSQL_STATEMENTS]; + WordList &kwDataTypes = *keywordlists[KW_MSSQL_DATA_TYPES]; + WordList &kwSystemTables = *keywordlists[KW_MSSQL_SYSTEM_TABLES]; + WordList &kwGlobalVariables = *keywordlists[KW_MSSQL_GLOBAL_VARIABLES]; + WordList &kwFunctions = *keywordlists[KW_MSSQL_FUNCTIONS]; + WordList &kwStoredProcedures = *keywordlists[KW_MSSQL_STORED_PROCEDURES]; + WordList &kwOperators = *keywordlists[KW_MSSQL_OPERATORS]; + + for (unsigned int i = 0; i < end - start + 1 && i < 128; i++) { + s[i] = static_cast<char>(tolower(styler[start + i])); + s[i + 1] = '\0'; + } + char chAttr = SCE_MSSQL_IDENTIFIER; + + if (actualState == SCE_MSSQL_GLOBAL_VARIABLE) { + + if (kwGlobalVariables.InList(&s[2])) + chAttr = SCE_MSSQL_GLOBAL_VARIABLE; + + } else if (wordIsNumber) { + chAttr = SCE_MSSQL_NUMBER; + + } else if (prevState == SCE_MSSQL_DEFAULT_PREF_DATATYPE) { + // Look first in datatypes + if (kwDataTypes.InList(s)) + chAttr = SCE_MSSQL_DATATYPE; + else if (kwOperators.InList(s)) + chAttr = SCE_MSSQL_OPERATOR; + else if (kwStatements.InList(s)) + chAttr = SCE_MSSQL_STATEMENT; + else if (kwSystemTables.InList(s)) + chAttr = SCE_MSSQL_SYSTABLE; + else if (kwFunctions.InList(s)) + chAttr = SCE_MSSQL_FUNCTION; + else if (kwStoredProcedures.InList(s)) + chAttr = SCE_MSSQL_STORED_PROCEDURE; + + } else { + if (kwOperators.InList(s)) + chAttr = SCE_MSSQL_OPERATOR; + else if (kwStatements.InList(s)) + chAttr = SCE_MSSQL_STATEMENT; + else if (kwSystemTables.InList(s)) + chAttr = SCE_MSSQL_SYSTABLE; + else if (kwFunctions.InList(s)) + chAttr = SCE_MSSQL_FUNCTION; + else if (kwStoredProcedures.InList(s)) + chAttr = SCE_MSSQL_STORED_PROCEDURE; + else if (kwDataTypes.InList(s)) + chAttr = SCE_MSSQL_DATATYPE; + } + + styler.ColourTo(end, chAttr); + + return chAttr; +} + +static void ColouriseMSSQLDoc(unsigned int startPos, int length, + int initStyle, WordList *keywordlists[], Accessor &styler) { + + + styler.StartAt(startPos); + + bool fold = styler.GetPropertyInt("fold") != 0; + int lineCurrent = styler.GetLine(startPos); + int spaceFlags = 0; + + int state = initStyle; + int prevState = initStyle; + char chPrev = ' '; + char chNext = styler[startPos]; + styler.StartSegment(startPos); + unsigned int lengthDoc = startPos + length; + for (unsigned int i = startPos; i < lengthDoc; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + + if ((ch == '\r' && chNext != '\n') || (ch == '\n')) { + int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags); + int lev = indentCurrent; + if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) { + // Only non whitespace lines can be headers + int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags); + if (indentCurrent < (indentNext & ~SC_FOLDLEVELWHITEFLAG)) { + lev |= SC_FOLDLEVELHEADERFLAG; + } + } + if (fold) { + styler.SetLevel(lineCurrent, lev); + } + } + + if (styler.IsLeadByte(ch)) { + chNext = styler.SafeGetCharAt(i + 2); + chPrev = ' '; + i += 1; + continue; + } + + // When the last char isn't part of the state (have to deal with it too)... + if ( (state == SCE_MSSQL_IDENTIFIER) || + (state == SCE_MSSQL_STORED_PROCEDURE) || + (state == SCE_MSSQL_DATATYPE) || + //~ (state == SCE_MSSQL_COLUMN_NAME) || + (state == SCE_MSSQL_FUNCTION) || + //~ (state == SCE_MSSQL_GLOBAL_VARIABLE) || + (state == SCE_MSSQL_VARIABLE)) { + if (!iswordchar(ch)) { + int stateTmp; + + if ((state == SCE_MSSQL_VARIABLE) || (state == SCE_MSSQL_COLUMN_NAME)) { + styler.ColourTo(i - 1, state); + stateTmp = state; + } else + stateTmp = classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState); + + prevState = state; + + if (stateTmp == SCE_MSSQL_IDENTIFIER || stateTmp == SCE_MSSQL_VARIABLE) + state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; + else + state = SCE_MSSQL_DEFAULT; + } + } else if (state == SCE_MSSQL_LINE_COMMENT) { + if (ch == '\r' || ch == '\n') { + styler.ColourTo(i - 1, state); + prevState = state; + state = SCE_MSSQL_DEFAULT; + } + } else if (state == SCE_MSSQL_GLOBAL_VARIABLE) { + if ((ch != '@') && !iswordchar(ch)) { + classifyWordSQL(styler.GetStartSegment(), i - 1, keywordlists, styler, state, prevState); + prevState = state; + state = SCE_MSSQL_DEFAULT; + } + } + + // If is the default or one of the above succeeded + if (state == SCE_MSSQL_DEFAULT || state == SCE_MSSQL_DEFAULT_PREF_DATATYPE) { + if (iswordstart(ch)) { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + prevState = state; + state = SCE_MSSQL_IDENTIFIER; + } else if (ch == '/' && chNext == '*') { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + prevState = state; + state = SCE_MSSQL_COMMENT; + } else if (ch == '-' && chNext == '-') { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + prevState = state; + state = SCE_MSSQL_LINE_COMMENT; + } else if (ch == '\'') { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + prevState = state; + state = SCE_MSSQL_STRING; + } else if (ch == '"') { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + prevState = state; + state = SCE_MSSQL_COLUMN_NAME; + } else if (ch == '[') { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + prevState = state; + state = SCE_MSSQL_COLUMN_NAME_2; + } else if (isMSSQLOperator(ch)) { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + styler.ColourTo(i, SCE_MSSQL_OPERATOR); + //~ style = SCE_MSSQL_DEFAULT; + prevState = state; + state = SCE_MSSQL_DEFAULT; + } else if (ch == '@') { + styler.ColourTo(i - 1, SCE_MSSQL_DEFAULT); + prevState = state; + if (chNext == '@') { + state = SCE_MSSQL_GLOBAL_VARIABLE; +// i += 2; + } else + state = SCE_MSSQL_VARIABLE; + } + + + // When the last char is part of the state... + } else if (state == SCE_MSSQL_COMMENT) { + if (ch == '/' && chPrev == '*') { + if (((i > (styler.GetStartSegment() + 2)) || ((initStyle == SCE_MSSQL_COMMENT) && + (styler.GetStartSegment() == startPos)))) { + styler.ColourTo(i, state); + //~ state = SCE_MSSQL_COMMENT; + prevState = state; + state = SCE_MSSQL_DEFAULT; + } + } + } else if (state == SCE_MSSQL_STRING) { + if (ch == '\'') { + if ( chNext == '\'' ) { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } else { + styler.ColourTo(i, state); + prevState = state; + state = SCE_MSSQL_DEFAULT; + //i++; + } + //ch = chNext; + //chNext = styler.SafeGetCharAt(i + 1); + } + } else if (state == SCE_MSSQL_COLUMN_NAME) { + if (ch == '"') { + if (chNext == '"') { + i++; + ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + } else { + styler.ColourTo(i, state); + prevState = state; + state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; + //i++; + } + } + } else if (state == SCE_MSSQL_COLUMN_NAME_2) { + if (ch == ']') { + styler.ColourTo(i, state); + prevState = state; + state = SCE_MSSQL_DEFAULT_PREF_DATATYPE; + //i++; + } + } + + chPrev = ch; + } + styler.ColourTo(lengthDoc - 1, state); +} + +static void FoldMSSQLDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { + bool foldComment = styler.GetPropertyInt("fold.comment") != 0; + bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0; + unsigned int endPos = startPos + length; + int visibleChars = 0; + int lineCurrent = styler.GetLine(startPos); + int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK; + int levelCurrent = levelPrev; + char chNext = styler[startPos]; + bool inComment = (styler.StyleAt(startPos-1) == SCE_MSSQL_COMMENT); + char s[10]; + for (unsigned int i = startPos; i < endPos; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + int style = styler.StyleAt(i); + bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); + // Comment folding + if (foldComment) { + if (!inComment && (style == SCE_MSSQL_COMMENT)) + levelCurrent++; + else if (inComment && (style != SCE_MSSQL_COMMENT)) + levelCurrent--; + inComment = (style == SCE_MSSQL_COMMENT); + } + if (style == SCE_MSSQL_STATEMENT) { + // Folding between begin and end + if (ch == 'b' || ch == 'e') { + for (unsigned int j = 0; j < 5; j++) { + if (!iswordchar(styler[i + j])) { + break; + } + s[j] = styler[i + j]; + s[j + 1] = '\0'; + } + if (strcmp(s, "begin") == 0) { + levelCurrent++; + } + if (strcmp(s, "end") == 0) { + levelCurrent--; + } + } + } + if (atEOL) { + int lev = levelPrev; + if (visibleChars == 0 && foldCompact) + lev |= SC_FOLDLEVELWHITEFLAG; + if ((levelCurrent > levelPrev) && (visibleChars > 0)) + lev |= SC_FOLDLEVELHEADERFLAG; + if (lev != styler.LevelAt(lineCurrent)) { + styler.SetLevel(lineCurrent, lev); + } + lineCurrent++; + levelPrev = levelCurrent; + visibleChars = 0; + } + if (!isspacechar(ch)) + visibleChars++; + } + // Fill in the real level of the next line, keeping the current flags as they will be filled in later + int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK; + styler.SetLevel(lineCurrent, levelPrev | flagsNext); +} + +static const char * const sqlWordListDesc[] = { + "Statements", + "Data Types", + "System tables", + "Global variables", + "Functions", + "System Stored Procedures", + "Operators", + 0, +}; + +LexerModule lmMSSQL(SCLEX_MSSQL, ColouriseMSSQLDoc, "mssql", FoldMSSQLDoc, sqlWordListDesc); |