diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/KeyWords.cxx | 1 | ||||
| -rw-r--r-- | src/LexNimrod.cxx | 426 | 
2 files changed, 427 insertions, 0 deletions
| diff --git a/src/KeyWords.cxx b/src/KeyWords.cxx index d5d7499df..5c8b1625f 100644 --- a/src/KeyWords.cxx +++ b/src/KeyWords.cxx @@ -195,6 +195,7 @@ int Scintilla_LinkLexers() {  	LINK_LEXER(lmMMIXAL);  	LINK_LEXER(lmMSSQL);  	LINK_LEXER(lmMySQL); +	LINK_LEXER(lmNimrod);  	LINK_LEXER(lmNncrontab);  	LINK_LEXER(lmNsis);  	LINK_LEXER(lmNull); diff --git a/src/LexNimrod.cxx b/src/LexNimrod.cxx new file mode 100644 index 000000000..fc8d05f0b --- /dev/null +++ b/src/LexNimrod.cxx @@ -0,0 +1,426 @@ +// Scintilla source code edit control +// Nimrod lexer +// (c) 2009 Andreas Rumpf +/** @file LexNimrod.cxx + ** Lexer for Nimrod. + **/ +// 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 <ctype.h> +#include <stdio.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "PropSet.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "KeyWords.h" +#include "Scintilla.h" +#include "SciLexer.h" + +static inline bool IsAWordChar(int ch) { +	return (ch >= 0x80) || isalnum(ch) || ch == '_'; +} + +static int tillEndOfTripleQuote(Accessor &styler, int pos, int max) { +  /* search for """ */ +  for (;;) { +    if (styler.SafeGetCharAt(pos, '\0') == '\0') return pos; +    if (pos >= max) return pos; +    if (styler.Match(pos, "\"\"\"")) { +      return pos + 2; +    } +    pos++; +  } +} + +#define CR 13 /* use both because Scite allows changing the line ending */ +#define LF 10 + +static bool inline isNewLine(int ch) { +  return ch == CR || ch == LF; +} + +static int scanString(Accessor &styler, int pos, int max, bool rawMode) { +  for (;;) { +    if (pos >= max) return pos; +    char ch = styler.SafeGetCharAt(pos, '\0'); +    if (ch == CR || ch == LF || ch == '\0') return pos; +    if (ch == '"') return pos; +    if (ch == '\\' && !rawMode) { +      pos += 2; +    } else { +      pos++; +    } +  } +} + +static int scanChar(Accessor &styler, int pos, int max) { +  for (;;) { +    if (pos >= max) return pos; +    char ch = styler.SafeGetCharAt(pos, '\0'); +    if (ch == CR || ch == LF || ch == '\0') return pos; +    if (ch == '\'' && !isalnum(styler.SafeGetCharAt(pos+1, '\0')) ) +      return pos; +    if (ch == '\\') { +      pos += 2; +    } else { +      pos++; +    } +  } +} + +static int scanIdent(Accessor &styler, int pos, WordList &keywords) { +  char buf[100]; /* copy to lowercase and ignore underscores */ +  int i = 0; + +  for (;;) { +    char ch = styler.SafeGetCharAt(pos, '\0'); +    if (!IsAWordChar(ch)) break; +    if (ch != '_' && i < ((int)sizeof(buf))-1) { +      buf[i] = static_cast<char>(tolower(ch)); +      i++; +    } +    pos++; +  } +  buf[i] = '\0'; +  /* look for keyword */ +  if (keywords.InList(buf)) { +    styler.ColourTo(pos-1, SCE_P_WORD); +  } else { +    styler.ColourTo(pos-1, SCE_P_IDENTIFIER); +  } +  return pos; +} + +static int scanNumber(Accessor &styler, int pos) { +  char ch, ch2; +  ch = styler.SafeGetCharAt(pos, '\0'); +  ch2 = styler.SafeGetCharAt(pos+1, '\0'); +  if (ch == '0' && (ch2 == 'b' || ch2 == 'B')) { +    /* binary number: */ +    pos += 2; +    for (;;) { +      ch = styler.SafeGetCharAt(pos, '\0'); +      if (ch == '_' || (ch >= '0' && ch <= '1')) ++pos; +      else break; +    } +  } else if (ch == '0' &&  +            (ch2 == 'o' || ch2 == 'O' || ch2 == 'c' || ch2 == 'C')) { +    /* octal number: */ +    pos += 2; +    for (;;) { +      ch = styler.SafeGetCharAt(pos, '\0'); +      if (ch == '_' || (ch >= '0' && ch <= '7')) ++pos; +      else break; +    } +  } else if (ch == '0' && (ch2 == 'x' || ch2 == 'X')) { +    /* hexadecimal number: */ +    pos += 2; +    for (;;) { +      ch = styler.SafeGetCharAt(pos, '\0'); +      if (ch == '_' || (ch >= '0' && ch <= '9') +          || (ch >= 'a' && ch <= 'f') +          || (ch >= 'A' && ch <= 'F')) ++pos; +      else break; +    } +  } else { +    // skip decimal part: +    for (;;) { +      ch = styler.SafeGetCharAt(pos, '\0'); +      if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; +      else break; +    } +    ch2 = styler.SafeGetCharAt(pos+1, '\0'); +    if (ch == '.' && ch2 >= '0' && ch2 <= '9') { +      ++pos; // skip '.' +      for (;;) { +        ch = styler.SafeGetCharAt(pos, '\0'); +        if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; +        else break; +      } +    } +    if (ch == 'e' || ch == 'E') { +      ++pos; +      ch = styler.SafeGetCharAt(pos, '\0'); +      if (ch == '-' || ch == '+') ++pos; +      for (;;) { +        ch = styler.SafeGetCharAt(pos, '\0'); +        if (ch == '_' || (ch >= '0' && ch <= '9')) ++pos; +        else break; +      } +    } +  } +  if (ch == '\'') { +    /* a type suffix: */ +    pos++; +    for (;;) { +      ch = styler.SafeGetCharAt(pos); +      if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') +         || (ch >= 'a' && ch <= 'z') || ch == '_') ++pos; +      else break; +    } +  } +  styler.ColourTo(pos-1, SCE_P_NUMBER); +  return pos; +} + +/* rewritten from scratch, because I couldn't get rid of the bugs... +   (A character based approach sucks!) +*/ +static void ColouriseNimrodDoc(unsigned int startPos, int length, int initStyle, +                                WordList *keywordlists[], Accessor &styler) { +  int pos = startPos; +  int max = startPos + length; +  char ch; +  WordList &keywords = *keywordlists[0]; + +  styler.StartAt(startPos); +  styler.StartSegment(startPos); + +  switch (initStyle) { +    /* check where we are: */ +    case SCE_P_TRIPLEDOUBLE: +      pos = tillEndOfTripleQuote(styler, pos, max); +      styler.ColourTo(pos, SCE_P_TRIPLEDOUBLE); +      pos++; +    break; +    default: /* nothing to do: */ +    break; +  } +  while (pos < max) { +    ch = styler.SafeGetCharAt(pos, '\0'); +    switch (ch) { +      case '\0': return; +      case '#': { +        bool doccomment = (styler.SafeGetCharAt(pos+1) == '#'); +        while (pos < max && !isNewLine(styler.SafeGetCharAt(pos, LF))) pos++; +        if (doccomment)  +          styler.ColourTo(pos, SCE_C_COMMENTLINEDOC); +        else +          styler.ColourTo(pos, SCE_P_COMMENTLINE); +      } break; +      case 'r': case 'R': { +        if (styler.SafeGetCharAt(pos+1) == '"') { +          pos = scanString(styler, pos+2, max, true); +          styler.ColourTo(pos, SCE_P_STRING); +          pos++; +        } else { +          pos = scanIdent(styler, pos, keywords); +        } +      } break; +      case '"': +        if (styler.Match(pos+1, "\"\"")) { +          pos = tillEndOfTripleQuote(styler, pos+3, max); +          styler.ColourTo(pos, SCE_P_TRIPLEDOUBLE); +        } else { +          pos = scanString(styler, pos+1, max, false); +          styler.ColourTo(pos, SCE_P_STRING); +        } +        pos++; +      break; +      case '\'': +        pos = scanChar(styler, pos+1, max); +        styler.ColourTo(pos, SCE_P_CHARACTER); +        pos++; +      break; +      default: // identifers, numbers, operators, whitespace +        if (ch >= '0' && ch <= '9') { +          pos = scanNumber(styler, pos); +        } else if (IsAWordChar(ch)) { +          pos = scanIdent(styler, pos, keywords); +        } else if (ch == '`') { +          pos++; +          while (pos < max) { +            ch = styler.SafeGetCharAt(pos, LF); +            if (ch == '`') { +              ++pos; +              break; +            } +            if (ch == CR || ch == LF) break; +            ++pos; +          } +          styler.ColourTo(pos, SCE_P_IDENTIFIER); +        } else if (strchr("()[]{}:=;-\\/&%$!+<>|^?,.*~@", ch)) { +          styler.ColourTo(pos, SCE_P_OPERATOR); +          pos++; +        } else { +          styler.ColourTo(pos, SCE_P_DEFAULT); +          pos++; +        } +      break; +    } +  } +} + +static bool IsCommentLine(int line, Accessor &styler) { +	int pos = styler.LineStart(line); +	int eol_pos = styler.LineStart(line + 1) - 1; +	for (int i = pos; i < eol_pos; i++) { +		char ch = styler[i]; +		if (ch == '#') +			return true; +		else if (ch != ' ' && ch != '\t') +			return false; +	} +	return false; +} + +static bool IsQuoteLine(int line, Accessor &styler) { +	int style = styler.StyleAt(styler.LineStart(line)) & 31; +	return ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE)); +} + + +static void FoldNimrodDoc(unsigned int startPos, int length,  +                          int /*initStyle - unused*/, +                          WordList *[], Accessor &styler) { +	const int maxPos = startPos + length; +	const int maxLines = styler.GetLine(maxPos - 1); // Requested last line +	const int docLines = styler.GetLine(styler.Length() - 1); // Available last line +	const bool foldComment = styler.GetPropertyInt("fold.comment.nimrod") != 0; +	const bool foldQuotes = styler.GetPropertyInt("fold.quotes.nimrod") != 0; + +	// Backtrack to previous non-blank line so we can determine indent level +	// for any white space lines (needed esp. within triple quoted strings) +	// and so we can fix any preceding fold level (which is why we go back +	// at least one line in all cases) +	int spaceFlags = 0; +	int lineCurrent = styler.GetLine(startPos); +	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); +	while (lineCurrent > 0) { +		lineCurrent--; +		indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL); +		if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) && +		        (!IsCommentLine(lineCurrent, styler)) && +		        (!IsQuoteLine(lineCurrent, styler))) +			break; +	} +	int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; + +	// Set up initial loop state +	startPos = styler.LineStart(lineCurrent); +	int prev_state = SCE_P_DEFAULT & 31; +	if (lineCurrent >= 1) +		prev_state = styler.StyleAt(startPos - 1) & 31; +	int prevQuote = foldQuotes && ((prev_state == SCE_P_TRIPLE) ||  +	                               (prev_state == SCE_P_TRIPLEDOUBLE)); +	int prevComment = 0; +	if (lineCurrent >= 1) +		prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler); + +	// Process all characters to end of requested range or end of any triple quote +	// or comment that hangs over the end of the range.  Cap processing in all cases +	// to end of document (in case of unclosed quote or comment at end). +	while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) ||  +	                                      prevQuote || prevComment)) { + +		// Gather info +		int lev = indentCurrent; +		int lineNext = lineCurrent + 1; +		int indentNext = indentCurrent; +		int quote = false; +		if (lineNext <= docLines) { +			// Information about next line is only available if not at end of document +			indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); +			int style = styler.StyleAt(styler.LineStart(lineNext)) & 31; +			quote = foldQuotes && ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE)); +		} +		const int quote_start = (quote && !prevQuote); +		const int quote_continue = (quote && prevQuote); +		const int comment = foldComment && IsCommentLine(lineCurrent, styler); +		const int comment_start = (comment && !prevComment && (lineNext <= docLines) && +		                           IsCommentLine(lineNext, styler) &&  +		                           (lev > SC_FOLDLEVELBASE)); +		const int comment_continue = (comment && prevComment); +		if ((!quote || !prevQuote) && !comment) +			indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; +		if (quote) +			indentNext = indentCurrentLevel; +		if (indentNext & SC_FOLDLEVELWHITEFLAG) +			indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel; + +		if (quote_start) { +			// Place fold point at start of triple quoted string +			lev |= SC_FOLDLEVELHEADERFLAG; +		} else if (quote_continue || prevQuote) { +			// Add level to rest of lines in the string +			lev = lev + 1; +		} else if (comment_start) { +			// Place fold point at start of a block of comments +			lev |= SC_FOLDLEVELHEADERFLAG; +		} else if (comment_continue) { +			// Add level to rest of lines in the block +			lev = lev + 1; +		} + +		// Skip past any blank lines for next indent level info; we skip also +		// comments (all comments, not just those starting in column 0) +		// which effectively folds them into surrounding code rather +		// than screwing up folding. + +		while (!quote && +		        (lineNext < docLines) && +		        ((indentNext & SC_FOLDLEVELWHITEFLAG) || +		         (lineNext <= docLines && IsCommentLine(lineNext, styler)))) { + +			lineNext++; +			indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); +		} + +		const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK; +		const int levelBeforeComments =  +		    Platform::Maximum(indentCurrentLevel,levelAfterComments); + +		// Now set all the indent levels on the lines we skipped +		// Do this from end to start.  Once we encounter one line +		// which is indented more than the line after the end of +		// the comment-block, use the level of the block before + +		int skipLine = lineNext; +		int skipLevel = levelAfterComments; + +		while (--skipLine > lineCurrent) { +			int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL); + +			if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments) +				skipLevel = levelBeforeComments; + +			int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG; + +			styler.SetLevel(skipLine, skipLevel | whiteFlag); +		} + +		// Set fold header on non-quote/non-comment line +		if (!quote && !comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) { +			if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) <  +			     (indentNext & SC_FOLDLEVELNUMBERMASK)) +				lev |= SC_FOLDLEVELHEADERFLAG; +		} + +		// Keep track of triple quote and block comment state of previous line +		prevQuote = quote; +		prevComment = comment_start || comment_continue; + +		// Set fold level for this line and move to next line +		styler.SetLevel(lineCurrent, lev); +		indentCurrent = indentNext; +		lineCurrent = lineNext; +	} + +	// NOTE: Cannot set level of last line here because indentCurrent doesn't have +	// header flag set; the loop above is crafted to take care of this case! +	//styler.SetLevel(lineCurrent, indentCurrent); +} + +static const char * const nimrodWordListDesc[] = { +	"Keywords", +	0 +}; + +LexerModule lmNimrod(SCLEX_NIMROD, ColouriseNimrodDoc, "nimrod", FoldNimrodDoc, +				     nimrodWordListDesc); | 
