diff options
Diffstat (limited to 'lexers/LexMSSQL.cxx')
| -rw-r--r-- | lexers/LexMSSQL.cxx | 363 | 
1 files changed, 363 insertions, 0 deletions
diff --git a/lexers/LexMSSQL.cxx b/lexers/LexMSSQL.cxx new file mode 100644 index 000000000..4a3f3bed8 --- /dev/null +++ b/lexers/LexMSSQL.cxx @@ -0,0 +1,363 @@ +// 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" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +#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 or case and end +            if (ch == 'b' || ch == 'B' || ch == 'c' || ch == 'C' || ch == 'e' || ch == 'E') { +                for (unsigned int j = 0; j < 5; j++) { +					if (!iswordchar(styler[i + j])) { +						break; +					} +					s[j] = static_cast<char>(tolower(styler[i + j])); +					s[j + 1] = '\0'; +                } +				if ((strcmp(s, "begin") == 0) || (strcmp(s, "case") == 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);  | 
