mirror of
				https://github.com/notepad-plus-plus/notepad-plus-plus.git
				synced 2025-10-31 03:24:04 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1266 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1266 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Scintilla source code edit control
 | ||
| // Encoding: UTF-8
 | ||
| /** @file LexJulia.cxx
 | ||
|  ** Lexer for Julia.
 | ||
|  ** Reusing code from LexMatlab, LexPython and LexRust
 | ||
|  **
 | ||
|  ** Written by Bertrand Lacoste
 | ||
|  **
 | ||
|  **/
 | ||
| // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
 | ||
| // The License.txt file describes the conditions under which this software may be distributed.
 | ||
| 
 | ||
| #include <cstdlib>
 | ||
| #include <cassert>
 | ||
| #include <cstring>
 | ||
| 
 | ||
| #include <string>
 | ||
| #include <string_view>
 | ||
| #include <vector>
 | ||
| #include <map>
 | ||
| #include <algorithm>
 | ||
| #include <functional>
 | ||
| 
 | ||
| #include "ILexer.h"
 | ||
| #include "Scintilla.h"
 | ||
| #include "SciLexer.h"
 | ||
| 
 | ||
| #include "StringCopy.h"
 | ||
| #include "PropSetSimple.h"
 | ||
| #include "WordList.h"
 | ||
| #include "LexAccessor.h"
 | ||
| #include "Accessor.h"
 | ||
| #include "StyleContext.h"
 | ||
| #include "CharacterSet.h"
 | ||
| #include "CharacterCategory.h"
 | ||
| #include "LexerModule.h"
 | ||
| #include "OptionSet.h"
 | ||
| #include "DefaultLexer.h"
 | ||
| 
 | ||
| using namespace Scintilla;
 | ||
| using namespace Lexilla;
 | ||
| 
 | ||
| static const int MAX_JULIA_IDENT_CHARS = 1023;
 | ||
| 
 | ||
| // Options used for LexerJulia
 | ||
| struct OptionsJulia {
 | ||
|     bool fold;
 | ||
|     bool foldComment;
 | ||
|     bool foldCompact;
 | ||
|     bool foldDocstring;
 | ||
|     bool foldSyntaxBased;
 | ||
|     bool highlightTypeannotation;
 | ||
|     bool highlightLexerror;
 | ||
| 	OptionsJulia() {
 | ||
|         fold = true;
 | ||
|         foldComment = true;
 | ||
|         foldCompact = false;
 | ||
|         foldDocstring = true;
 | ||
|         foldSyntaxBased = true;
 | ||
|         highlightTypeannotation = false;
 | ||
|         highlightLexerror = false;
 | ||
| 	}
 | ||
| };
 | ||
| 
 | ||
| const char * const juliaWordLists[] = {
 | ||
|     "Primary keywords and identifiers",
 | ||
|     "Built in types",
 | ||
|     "Other keywords",
 | ||
|     "Built in functions",
 | ||
|     0,
 | ||
| };
 | ||
| 
 | ||
| struct OptionSetJulia : public OptionSet<OptionsJulia> {
 | ||
| 	OptionSetJulia() {
 | ||
| 		DefineProperty("fold", &OptionsJulia::fold);
 | ||
| 
 | ||
| 		DefineProperty("fold.compact", &OptionsJulia::foldCompact);
 | ||
| 
 | ||
| 		DefineProperty("fold.comment", &OptionsJulia::foldComment);
 | ||
| 
 | ||
| 		DefineProperty("fold.julia.docstring", &OptionsJulia::foldDocstring,
 | ||
| 			"Fold multiline triple-doublequote strings, usually used to document a function or type above the definition.");
 | ||
| 
 | ||
| 		DefineProperty("fold.julia.syntax.based", &OptionsJulia::foldSyntaxBased,
 | ||
| 			"Set this property to 0 to disable syntax based folding.");
 | ||
| 
 | ||
| 		DefineProperty("lexer.julia.highlight.typeannotation", &OptionsJulia::highlightTypeannotation,
 | ||
| 			"This option enables highlighting of the type identifier after `::`.");
 | ||
| 
 | ||
| 		DefineProperty("lexer.julia.highlight.lexerror", &OptionsJulia::highlightLexerror,
 | ||
| 			"This option enables highlighting of syntax error int character or number definition.");
 | ||
| 
 | ||
| 		DefineWordListSets(juliaWordLists);
 | ||
| 	}
 | ||
| };
 | ||
| 
 | ||
| LexicalClass juliaLexicalClasses[] = {
 | ||
| 	// Lexer Julia SCLEX_JULIA SCE_JULIA_:
 | ||
| 	0,  "SCE_JULIA_DEFAULT", "default", "White space",
 | ||
| 	1,  "SCE_JULIA_COMMENT", "comment", "Comment",
 | ||
| 	2,  "SCE_JULIA_NUMBER", "literal numeric", "Number",
 | ||
| 	3,  "SCE_JULIA_KEYWORD1", "keyword", "Reserved keywords",
 | ||
| 	4,  "SCE_JULIA_KEYWORD2", "identifier", "Builtin type names",
 | ||
| 	5,  "SCE_JULIA_KEYWORD3", "identifier", "Constants",
 | ||
| 	6,  "SCE_JULIA_CHAR", "literal string character", "Single quoted string",
 | ||
| 	7,  "SCE_JULIA_OPERATOR", "operator", "Operator",
 | ||
| 	8,  "SCE_JULIA_BRACKET", "bracket operator", "Bracket operator",
 | ||
| 	9,  "SCE_JULIA_IDENTIFIER", "identifier", "Identifier",
 | ||
| 	10, "SCE_JULIA_STRING", "literal string", "Double quoted String",
 | ||
| 	11, "SCE_JULIA_SYMBOL", "literal string symbol", "Symbol",
 | ||
| 	12, "SCE_JULIA_MACRO", "macro preprocessor", "Macro",
 | ||
| 	13, "SCE_JULIA_STRINGINTERP", "literal string interpolated", "String interpolation",
 | ||
| 	14, "SCE_JULIA_DOCSTRING", "literal string documentation", "Docstring",
 | ||
| 	15, "SCE_JULIA_STRINGLITERAL", "literal string", "String literal prefix",
 | ||
| 	16, "SCE_JULIA_COMMAND", "literal string command", "Command",
 | ||
| 	17, "SCE_JULIA_COMMANDLITERAL", "literal string command", "Command literal prefix",
 | ||
| 	18, "SCE_JULIA_TYPEANNOT", "identifier type", "Type annotation identifier",
 | ||
| 	19, "SCE_JULIA_LEXERROR", "lexer error", "Lexing error",
 | ||
| 	20, "SCE_JULIA_KEYWORD4", "identifier", "Builtin function names",
 | ||
| 	21, "SCE_JULIA_TYPEOPERATOR", "operator type", "Type annotation operator",
 | ||
| };
 | ||
| 
 | ||
| class LexerJulia : public DefaultLexer {
 | ||
| 	WordList keywords;
 | ||
| 	WordList identifiers2;
 | ||
| 	WordList identifiers3;
 | ||
| 	WordList identifiers4;
 | ||
| 	OptionsJulia options;
 | ||
| 	OptionSetJulia osJulia;
 | ||
| public:
 | ||
| 	explicit LexerJulia() :
 | ||
| 		DefaultLexer("julia", SCLEX_JULIA, juliaLexicalClasses, ELEMENTS(juliaLexicalClasses)) {
 | ||
| 	}
 | ||
| 	virtual ~LexerJulia() {
 | ||
| 	}
 | ||
| 	void SCI_METHOD Release() override {
 | ||
| 		delete this;
 | ||
| 	}
 | ||
| 	int SCI_METHOD Version() const override {
 | ||
| 		return lvRelease5;
 | ||
| 	}
 | ||
| 	const char * SCI_METHOD PropertyNames() override {
 | ||
| 		return osJulia.PropertyNames();
 | ||
| 	}
 | ||
| 	int SCI_METHOD PropertyType(const char *name) override {
 | ||
| 		return osJulia.PropertyType(name);
 | ||
| 	}
 | ||
| 	const char * SCI_METHOD DescribeProperty(const char *name) override {
 | ||
| 		return osJulia.DescribeProperty(name);
 | ||
| 	}
 | ||
| 	Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
 | ||
| 	const char * SCI_METHOD PropertyGet(const char *key) override {
 | ||
| 		return osJulia.PropertyGet(key);
 | ||
| 	}
 | ||
| 	const char * SCI_METHOD DescribeWordListSets() override {
 | ||
| 		return osJulia.DescribeWordListSets();
 | ||
| 	}
 | ||
| 	Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
 | ||
| 	void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
 | ||
| 	void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
 | ||
| 	void * SCI_METHOD PrivateCall(int, void *) override {
 | ||
| 		return 0;
 | ||
| 	}
 | ||
| 
 | ||
| 	static ILexer5 *LexerFactoryJulia() {
 | ||
| 		return new LexerJulia();
 | ||
| 	}
 | ||
| };
 | ||
| 
 | ||
| Sci_Position SCI_METHOD LexerJulia::PropertySet(const char *key, const char *val) {
 | ||
| 	if (osJulia.PropertySet(&options, key, val)) {
 | ||
| 		return 0;
 | ||
| 	}
 | ||
| 	return -1;
 | ||
| }
 | ||
| 
 | ||
| Sci_Position SCI_METHOD LexerJulia::WordListSet(int n, const char *wl) {
 | ||
| 	WordList *wordListN = nullptr;
 | ||
| 	switch (n) {
 | ||
| 	case 0:
 | ||
| 		wordListN = &keywords;
 | ||
| 		break;
 | ||
| 	case 1:
 | ||
| 		wordListN = &identifiers2;
 | ||
| 		break;
 | ||
| 	case 2:
 | ||
| 		wordListN = &identifiers3;
 | ||
| 		break;
 | ||
| 	case 3:
 | ||
| 		wordListN = &identifiers4;
 | ||
| 		break;
 | ||
| 	}
 | ||
| 	Sci_Position firstModification = -1;
 | ||
| 	if (wordListN) {
 | ||
| 		WordList wlNew;
 | ||
| 		wlNew.Set(wl);
 | ||
| 		if (*wordListN != wlNew) {
 | ||
| 			wordListN->Set(wl);
 | ||
| 			firstModification = 0;
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return firstModification;
 | ||
| }
 | ||
| 
 | ||
| static inline bool IsJuliaOperator(int ch) {
 | ||
|     if (ch == '%' || ch == '^' || ch == '&' || ch == '*' ||
 | ||
|         ch == '-' || ch == '+' || ch == '=' || ch == '|' ||
 | ||
|         ch == '<' || ch == '>' || ch == '/' || ch == '~' ||
 | ||
|         ch == '\\' ) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| // The list contains non-ascii unary operators
 | ||
| static inline bool IsJuliaUnaryOperator (int ch) {
 | ||
|     if (ch == 0x00ac || ch == 0x221a || ch == 0x221b ||
 | ||
|         ch == 0x221c || ch == 0x22c6 || ch == 0x00b1 ||
 | ||
|         ch == 0x2213 ) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| static inline bool IsJuliaParen (int ch) {
 | ||
|     if (ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
 | ||
|         ch == '[' || ch == ']' ) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| // Unicode parsing from Julia source code:
 | ||
| // https://github.com/JuliaLang/julia/blob/master/src/flisp/julia_extensions.c
 | ||
| // keep the same function name to be easy to find again
 | ||
| static int is_wc_cat_id_start(uint32_t wc) {
 | ||
|     const CharacterCategory cat = CategoriseCharacter((int) wc);
 | ||
| 
 | ||
|     return (cat == ccLu || cat == ccLl ||
 | ||
|             cat == ccLt || cat == ccLm ||
 | ||
|             cat == ccLo || cat == ccNl ||
 | ||
|             cat == ccSc ||  // allow currency symbols
 | ||
|             // other symbols, but not arrows or replacement characters
 | ||
|             (cat == ccSo && !(wc >= 0x2190 && wc <= 0x21FF) &&
 | ||
|              wc != 0xfffc && wc != 0xfffd &&
 | ||
|              wc != 0x233f &&  // notslash
 | ||
|              wc != 0x00a6) || // broken bar
 | ||
| 
 | ||
|             // math symbol (category Sm) whitelist
 | ||
|             (wc >= 0x2140 && wc <= 0x2a1c &&
 | ||
|              ((wc >= 0x2140 && wc <= 0x2144) || // ⅀, ⅁, ⅂, ⅃, ⅄
 | ||
|               wc == 0x223f || wc == 0x22be || wc == 0x22bf || // ∿, ⊾, ⊿
 | ||
|               wc == 0x22a4 || wc == 0x22a5 ||   // ⊤ ⊥
 | ||
| 
 | ||
|               (wc >= 0x2200 && wc <= 0x2233 &&
 | ||
|                (wc == 0x2202 || wc == 0x2205 || wc == 0x2206 || // ∂, ∅, ∆
 | ||
|                 wc == 0x2207 || wc == 0x220e || wc == 0x220f || // ∇, ∎, ∏
 | ||
|                 wc == 0x2200 || wc == 0x2203 || wc == 0x2204 || // ∀, ∃, ∄
 | ||
|                 wc == 0x2210 || wc == 0x2211 || // ∐, ∑
 | ||
|                 wc == 0x221e || wc == 0x221f || // ∞, ∟
 | ||
|                 wc >= 0x222b)) || // ∫, ∬, ∭, ∮, ∯, ∰, ∱, ∲, ∳
 | ||
| 
 | ||
|               (wc >= 0x22c0 && wc <= 0x22c3) ||  // N-ary big ops: ⋀, ⋁, ⋂, ⋃
 | ||
|               (wc >= 0x25F8 && wc <= 0x25ff) ||  // ◸, ◹, ◺, ◻, ◼, ◽, ◾, ◿
 | ||
| 
 | ||
|               (wc >= 0x266f &&
 | ||
|                (wc == 0x266f || wc == 0x27d8 || wc == 0x27d9 || // ♯, ⟘, ⟙
 | ||
|                 (wc >= 0x27c0 && wc <= 0x27c1) ||  // ⟀, ⟁
 | ||
|                 (wc >= 0x29b0 && wc <= 0x29b4) ||  // ⦰, ⦱, ⦲, ⦳, ⦴
 | ||
|                 (wc >= 0x2a00 && wc <= 0x2a06) ||  // ⨀, ⨁, ⨂, ⨃, ⨄, ⨅, ⨆
 | ||
|                 (wc >= 0x2a09 && wc <= 0x2a16) ||  // ⨉, ⨊, ⨋, ⨌, ⨍, ⨎, ⨏, ⨐, ⨑, ⨒, ⨓, ⨔, ⨕, ⨖
 | ||
|                 wc == 0x2a1b || wc == 0x2a1c)))) || // ⨛, ⨜
 | ||
| 
 | ||
|             (wc >= 0x1d6c1 && // variants of \nabla and \partial
 | ||
|              (wc == 0x1d6c1 || wc == 0x1d6db ||
 | ||
|               wc == 0x1d6fb || wc == 0x1d715 ||
 | ||
|               wc == 0x1d735 || wc == 0x1d74f ||
 | ||
|               wc == 0x1d76f || wc == 0x1d789 ||
 | ||
|               wc == 0x1d7a9 || wc == 0x1d7c3)) ||
 | ||
| 
 | ||
|             // super- and subscript +-=()
 | ||
|             (wc >= 0x207a && wc <= 0x207e) ||
 | ||
|             (wc >= 0x208a && wc <= 0x208e) ||
 | ||
| 
 | ||
|             // angle symbols
 | ||
|             (wc >= 0x2220 && wc <= 0x2222) || // ∠, ∡, ∢
 | ||
|             (wc >= 0x299b && wc <= 0x29af) || // ⦛, ⦜, ⦝, ⦞, ⦟, ⦠, ⦡, ⦢, ⦣, ⦤, ⦥, ⦦, ⦧, ⦨, ⦩, ⦪, ⦫, ⦬, ⦭, ⦮, ⦯
 | ||
| 
 | ||
|             // Other_ID_Start
 | ||
|             wc == 0x2118 || wc == 0x212E || // ℘, ℮
 | ||
|             (wc >= 0x309B && wc <= 0x309C) || // katakana-hiragana sound marks
 | ||
| 
 | ||
|             // bold-digits and double-struck digits
 | ||
|             (wc >= 0x1D7CE && wc <= 0x1D7E1)); // 𝟎 through 𝟗 (inclusive), 𝟘 through 𝟡 (inclusive)
 | ||
| }
 | ||
| 
 | ||
| static inline bool IsIdentifierFirstCharacter (int ch) {
 | ||
|     if (IsASCII(ch)) {
 | ||
|         return (bool) (isalpha(ch) || ch == '_');
 | ||
|     }
 | ||
|     if (ch < 0xA1 || ch > 0x10ffff) {
 | ||
|         return false;
 | ||
|     }
 | ||
| 
 | ||
|     return is_wc_cat_id_start((uint32_t) ch);
 | ||
| }
 | ||
| 
 | ||
| static inline bool IsIdentifierCharacter (int ch) {
 | ||
|     if (IsASCII(ch)) {
 | ||
|         return (bool) (isalnum(ch) || ch == '_' || ch == '!');
 | ||
|     }
 | ||
|     if (ch < 0xA1 || ch > 0x10ffff) {
 | ||
|         return false;
 | ||
|     }
 | ||
| 
 | ||
|     if (is_wc_cat_id_start((uint32_t) ch)) {
 | ||
|         return true;
 | ||
|     }
 | ||
| 
 | ||
|     const CharacterCategory cat = CategoriseCharacter(ch);
 | ||
| 
 | ||
|     if (cat == ccMn || cat == ccMc ||
 | ||
|         cat == ccNd || cat == ccPc ||
 | ||
|         cat == ccSk || cat == ccMe ||
 | ||
|         cat == ccNo ||
 | ||
|         // primes (single, double, triple, their reverses, and quadruple)
 | ||
|         (ch >= 0x2032 && ch <= 0x2037) || (ch == 0x2057)) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| // keep the same function name to be easy to find again
 | ||
| static const uint32_t opsuffs[] = {
 | ||
|    0x00b2, // ²
 | ||
|    0x00b3, // ³
 | ||
|    0x00b9, // ¹
 | ||
|    0x02b0, // ʰ
 | ||
|    0x02b2, // ʲ
 | ||
|    0x02b3, // ʳ
 | ||
|    0x02b7, // ʷ
 | ||
|    0x02b8, // ʸ
 | ||
|    0x02e1, // ˡ
 | ||
|    0x02e2, // ˢ
 | ||
|    0x02e3, // ˣ
 | ||
|    0x1d2c, // ᴬ
 | ||
|    0x1d2e, // ᴮ
 | ||
|    0x1d30, // ᴰ
 | ||
|    0x1d31, // ᴱ
 | ||
|    0x1d33, // ᴳ
 | ||
|    0x1d34, // ᴴ
 | ||
|    0x1d35, // ᴵ
 | ||
|    0x1d36, // ᴶ
 | ||
|    0x1d37, // ᴷ
 | ||
|    0x1d38, // ᴸ
 | ||
|    0x1d39, // ᴹ
 | ||
|    0x1d3a, // ᴺ
 | ||
|    0x1d3c, // ᴼ
 | ||
|    0x1d3e, // ᴾ
 | ||
|    0x1d3f, // ᴿ
 | ||
|    0x1d40, // ᵀ
 | ||
|    0x1d41, // ᵁ
 | ||
|    0x1d42, // ᵂ
 | ||
|    0x1d43, // ᵃ
 | ||
|    0x1d47, // ᵇ
 | ||
|    0x1d48, // ᵈ
 | ||
|    0x1d49, // ᵉ
 | ||
|    0x1d4d, // ᵍ
 | ||
|    0x1d4f, // ᵏ
 | ||
|    0x1d50, // ᵐ
 | ||
|    0x1d52, // ᵒ
 | ||
|    0x1d56, // ᵖ
 | ||
|    0x1d57, // ᵗ
 | ||
|    0x1d58, // ᵘ
 | ||
|    0x1d5b, // ᵛ
 | ||
|    0x1d5d, // ᵝ
 | ||
|    0x1d5e, // ᵞ
 | ||
|    0x1d5f, // ᵟ
 | ||
|    0x1d60, // ᵠ
 | ||
|    0x1d61, // ᵡ
 | ||
|    0x1d62, // ᵢ
 | ||
|    0x1d63, // ᵣ
 | ||
|    0x1d64, // ᵤ
 | ||
|    0x1d65, // ᵥ
 | ||
|    0x1d66, // ᵦ
 | ||
|    0x1d67, // ᵧ
 | ||
|    0x1d68, // ᵨ
 | ||
|    0x1d69, // ᵩ
 | ||
|    0x1d6a, // ᵪ
 | ||
|    0x1d9c, // ᶜ
 | ||
|    0x1da0, // ᶠ
 | ||
|    0x1da5, // ᶥ
 | ||
|    0x1da6, // ᶦ
 | ||
|    0x1dab, // ᶫ
 | ||
|    0x1db0, // ᶰ
 | ||
|    0x1db8, // ᶸ
 | ||
|    0x1dbb, // ᶻ
 | ||
|    0x1dbf, // ᶿ
 | ||
|    0x2032, // ′
 | ||
|    0x2033, // ″
 | ||
|    0x2034, // ‴
 | ||
|    0x2035, // ‵
 | ||
|    0x2036, // ‶
 | ||
|    0x2037, // ‷
 | ||
|    0x2057, // ⁗
 | ||
|    0x2070, // ⁰
 | ||
|    0x2071, // ⁱ
 | ||
|    0x2074, // ⁴
 | ||
|    0x2075, // ⁵
 | ||
|    0x2076, // ⁶
 | ||
|    0x2077, // ⁷
 | ||
|    0x2078, // ⁸
 | ||
|    0x2079, // ⁹
 | ||
|    0x207a, // ⁺
 | ||
|    0x207b, // ⁻
 | ||
|    0x207c, // ⁼
 | ||
|    0x207d, // ⁽
 | ||
|    0x207e, // ⁾
 | ||
|    0x207f, // ⁿ
 | ||
|    0x2080, // ₀
 | ||
|    0x2081, // ₁
 | ||
|    0x2082, // ₂
 | ||
|    0x2083, // ₃
 | ||
|    0x2084, // ₄
 | ||
|    0x2085, // ₅
 | ||
|    0x2086, // ₆
 | ||
|    0x2087, // ₇
 | ||
|    0x2088, // ₈
 | ||
|    0x2089, // ₉
 | ||
|    0x208a, // ₊
 | ||
|    0x208b, // ₋
 | ||
|    0x208c, // ₌
 | ||
|    0x208d, // ₍
 | ||
|    0x208e, // ₎
 | ||
|    0x2090, // ₐ
 | ||
|    0x2091, // ₑ
 | ||
|    0x2092, // ₒ
 | ||
|    0x2093, // ₓ
 | ||
|    0x2095, // ₕ
 | ||
|    0x2096, // ₖ
 | ||
|    0x2097, // ₗ
 | ||
|    0x2098, // ₘ
 | ||
|    0x2099, // ₙ
 | ||
|    0x209a, // ₚ
 | ||
|    0x209b, // ₛ
 | ||
|    0x209c, // ₜ
 | ||
|    0x2c7c, // ⱼ
 | ||
|    0x2c7d, // ⱽ
 | ||
|    0xa71b, // ꜛ
 | ||
|    0xa71c, // ꜜ
 | ||
|    0xa71d  // ꜝ
 | ||
| };
 | ||
| static const size_t opsuffs_len = sizeof(opsuffs) / (sizeof(uint32_t));
 | ||
| 
 | ||
| // keep the same function name to be easy to find again
 | ||
| static bool jl_op_suffix_char(uint32_t wc) {
 | ||
|     if (wc < 0xA1 || wc > 0x10ffff) {
 | ||
|         return false;
 | ||
|     }
 | ||
|     const CharacterCategory cat = CategoriseCharacter((int) wc);
 | ||
|     if (cat == ccMn || cat == ccMc ||
 | ||
|         cat == ccMe) {
 | ||
|         return true;
 | ||
|     }
 | ||
| 
 | ||
|     for (size_t i = 0; i < opsuffs_len; ++i) {
 | ||
|         if (wc == opsuffs[i]) {
 | ||
|             return true;
 | ||
|         }
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| // keep the same function name to be easy to find again
 | ||
| static bool never_id_char(uint32_t wc) {
 | ||
|      const CharacterCategory cat = CategoriseCharacter((int) wc);
 | ||
|      return (
 | ||
|           // spaces and control characters:
 | ||
|           (cat >= ccZs && cat <= ccCs) ||
 | ||
| 
 | ||
|           // ASCII and Latin1 non-connector punctuation
 | ||
|           (wc < 0xff &&
 | ||
|            cat >= ccPd && cat <= ccPo) ||
 | ||
| 
 | ||
|           wc == '`' ||
 | ||
| 
 | ||
|           // mathematical brackets
 | ||
|           (wc >= 0x27e6 && wc <= 0x27ef) ||
 | ||
|           // angle, corner, and lenticular brackets
 | ||
|           (wc >= 0x3008 && wc <= 0x3011) ||
 | ||
|           // tortoise shell, square, and more lenticular brackets
 | ||
|           (wc >= 0x3014 && wc <= 0x301b) ||
 | ||
|           // fullwidth parens
 | ||
|           (wc == 0xff08 || wc == 0xff09) ||
 | ||
|           // fullwidth square brackets
 | ||
|           (wc == 0xff3b || wc == 0xff3d));
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| static bool IsOperatorFirstCharacter (int ch) {
 | ||
|     if (IsASCII(ch)) {
 | ||
|         if (IsJuliaOperator(ch) ||
 | ||
|             ch == '!' || ch == '?' ||
 | ||
|             ch == ':' || ch == ';' ||
 | ||
|             ch == ',' || ch == '.' ) {
 | ||
|             return true;
 | ||
|         }else {
 | ||
|             return false;
 | ||
|         }
 | ||
|     } else if (is_wc_cat_id_start((uint32_t) ch)) {
 | ||
|         return false;
 | ||
|     } else if (IsJuliaUnaryOperator(ch) ||
 | ||
|                ! never_id_char((uint32_t) ch)) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| static bool IsOperatorCharacter (int ch) {
 | ||
|     if (IsOperatorFirstCharacter(ch) ||
 | ||
|         (!IsASCII(ch) && jl_op_suffix_char((uint32_t) ch)) ) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| static bool CheckBoundsIndexing(char *str) {
 | ||
|     if (strcmp("begin", str) == 0 || strcmp("end", str) == 0 ) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| static int CheckKeywordFoldPoint(char *str) {
 | ||
|     if (strcmp ("if", str) == 0 ||
 | ||
|         strcmp ("for", str) == 0 ||
 | ||
|         strcmp ("while", str) == 0 ||
 | ||
|         strcmp ("try", str) == 0 ||
 | ||
|         strcmp ("do", str) == 0 ||
 | ||
|         strcmp ("begin", str) == 0 ||
 | ||
|         strcmp ("let", str) == 0 ||
 | ||
|         strcmp ("baremodule", str) == 0 ||
 | ||
|         strcmp ("quote", str) == 0 ||
 | ||
|         strcmp ("module", str) == 0 ||
 | ||
|         strcmp ("struct", str) == 0 ||
 | ||
|         strcmp ("type", str) == 0 ||
 | ||
|         strcmp ("macro", str) == 0 ||
 | ||
|         strcmp ("function", str) == 0) {
 | ||
|         return 1;
 | ||
|     }
 | ||
|     if (strcmp("end", str) == 0) {
 | ||
|         return -1;
 | ||
|     }
 | ||
|     return 0;
 | ||
| }
 | ||
| 
 | ||
| static bool IsNumberExpon(int ch, int base) {
 | ||
|     if ((base == 10 && (ch == 'e' || ch == 'E' || ch == 'f')) ||
 | ||
|         (base == 16 && (ch == 'p' || ch == 'P'))) {
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| }
 | ||
| 
 | ||
| /* Scans a sequence of digits, returning true if it found any. */
 | ||
| static bool ScanDigits(StyleContext& sc, int base, bool allow_sep) {
 | ||
| 	bool found = false;
 | ||
|     for (;;) {
 | ||
| 		if (IsADigit(sc.chNext, base) || (allow_sep && sc.chNext == '_')) {
 | ||
| 			found = true;
 | ||
|             sc.Forward();
 | ||
| 		} else {
 | ||
| 			break;
 | ||
|         }
 | ||
| 	}
 | ||
| 	return found;
 | ||
| }
 | ||
| 
 | ||
| static inline bool ScanNHexas(StyleContext &sc, int max) {
 | ||
|     int n = 0;
 | ||
|     bool error = false;
 | ||
| 
 | ||
|     sc.Forward();
 | ||
|     if (!IsADigit(sc.ch, 16)) {
 | ||
|         error = true;
 | ||
|     } else {
 | ||
|         while (IsADigit(sc.ch, 16) && n < max) {
 | ||
|             sc.Forward();
 | ||
|             n++;
 | ||
|         }
 | ||
|     }
 | ||
|     return error;
 | ||
| }
 | ||
| 
 | ||
| static void resumeCharacter(StyleContext &sc, bool lexerror) {
 | ||
|     bool error = false;
 | ||
| 
 | ||
|     //  ''' case
 | ||
|     if (sc.chPrev == '\'' && sc.ch == '\'' && sc.chNext == '\'') {
 | ||
|         sc.Forward();
 | ||
|         sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|         return;
 | ||
|     } else if (lexerror && sc.chPrev == '\'' && sc.ch == '\'') {
 | ||
|         sc.ChangeState(SCE_JULIA_LEXERROR);
 | ||
|         sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
| 
 | ||
|     // Escape characters
 | ||
|     } else if (sc.ch == '\\') {
 | ||
|         sc.Forward();
 | ||
|         if (sc.ch == '\'' || sc.ch == '\\' ) {
 | ||
|             sc.Forward();
 | ||
|         } else if (sc.ch == 'n' || sc.ch == 't' || sc.ch == 'a' ||
 | ||
|                    sc.ch == 'b' || sc.ch == 'e' || sc.ch == 'f' ||
 | ||
|                    sc.ch == 'r' || sc.ch == 'v' ) {
 | ||
|             sc.Forward();
 | ||
|         } else if (sc.ch == 'x') {
 | ||
|             error |= ScanNHexas(sc, 2);
 | ||
|         } else if (sc.ch == 'u') {
 | ||
|             error |= ScanNHexas(sc, 4);
 | ||
|         } else if (sc.ch == 'U') {
 | ||
|             error |= ScanNHexas(sc, 8);
 | ||
|         } else if (IsADigit(sc.ch, 8)) {
 | ||
|             int n = 1;
 | ||
|             int max = 3;
 | ||
|             sc.Forward();
 | ||
|             while (IsADigit(sc.ch, 8) && n < max) {
 | ||
|                 sc.Forward();
 | ||
|                 n++;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         if (lexerror) {
 | ||
|             if (sc.ch != '\'') {
 | ||
|                 error = true;
 | ||
|                 while (sc.ch != '\'' &&
 | ||
|                        sc.ch != '\r' &&
 | ||
|                        sc.ch != '\n') {
 | ||
|                     sc.Forward();
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             if (error) {
 | ||
|                 sc.ChangeState(SCE_JULIA_LEXERROR);
 | ||
|                 sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|             }
 | ||
|         }
 | ||
|     } else if (lexerror) {
 | ||
|         if (sc.ch < 0x20 || sc.ch > 0x10ffff) {
 | ||
|             error = true;
 | ||
|         } else {
 | ||
|             // single character
 | ||
|             sc.Forward();
 | ||
| 
 | ||
|             if (sc.ch != '\'') {
 | ||
|                 error = true;
 | ||
|                 while (sc.ch != '\'' &&
 | ||
|                        sc.ch != '\r' &&
 | ||
|                        sc.ch != '\n') {
 | ||
|                     sc.Forward();
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         if (error) {
 | ||
|             sc.ChangeState(SCE_JULIA_LEXERROR);
 | ||
|             sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     // closing quote
 | ||
|     if (sc.ch == '\'') {
 | ||
|         if (sc.chNext == '\'') {
 | ||
|             sc.Forward();
 | ||
|         } else {
 | ||
|             sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static inline bool IsACharacter(StyleContext &sc) {
 | ||
|     return (sc.chPrev == '\'' && sc.chNext == '\'');
 | ||
| }
 | ||
| 
 | ||
| static void ScanParenInterpolation(StyleContext &sc) {
 | ||
|     // TODO: no syntax highlighting inside a string interpolation
 | ||
| 
 | ||
|     // Level of nested parenthesis
 | ||
|     int interp_level = 0;
 | ||
| 
 | ||
|     // If true, it is inside a string and parenthesis are not counted.
 | ||
|     bool allow_paren_string = false;
 | ||
| 
 | ||
| 
 | ||
|     // check for end of states
 | ||
|     for (; sc.More(); sc.Forward()) {
 | ||
|         // TODO: check corner cases for nested string interpolation
 | ||
|         // TODO: check corner cases with Command inside interpolation
 | ||
| 
 | ||
|         if ( sc.ch == '\"' && sc.chPrev != '\\') {
 | ||
|             // Toggle the string environment (parenthesis are not counted inside a string)
 | ||
|             allow_paren_string = !allow_paren_string;
 | ||
|         } else if ( !allow_paren_string ) {
 | ||
|             if ( sc.ch == '(' && !IsACharacter(sc) ) {
 | ||
|                 interp_level ++;
 | ||
|             } else if ( sc.ch == ')' && !IsACharacter(sc) && interp_level > 0 ) {
 | ||
|                 interp_level --;
 | ||
|                 if (interp_level == 0) {
 | ||
|                     // Exit interpolation
 | ||
|                     return;
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| /*
 | ||
|  * Start parsing a number, parse the base.
 | ||
|  */
 | ||
| static void initNumber (StyleContext &sc, int &base, bool &with_dot) {
 | ||
|     base = 10;
 | ||
|     with_dot = false;
 | ||
|     sc.SetState(SCE_JULIA_NUMBER);
 | ||
|     if (sc.ch == '0') {
 | ||
|         if (sc.chNext == 'x') {
 | ||
|             sc.Forward();
 | ||
|             base = 16;
 | ||
|             if (sc.chNext == '.') {
 | ||
|                 sc.Forward();
 | ||
|                 with_dot = true;
 | ||
|             }
 | ||
|         } else if (sc.chNext == 'o') {
 | ||
|             sc.Forward();
 | ||
|             base = 8;
 | ||
|         } else if (sc.chNext == 'b') {
 | ||
|             sc.Forward();
 | ||
|             base = 2;
 | ||
|         }
 | ||
|     } else if (sc.ch == '.') {
 | ||
|         with_dot = true;
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| /*
 | ||
|  * Resume parsing a String or Command, bounded by the `quote` character (\" or \`)
 | ||
|  * The `triple` argument specifies if it is a triple-quote String or Command.
 | ||
|  * Interpolation is detected (with `$`), and parsed if `allow_interp` is true.
 | ||
|  */
 | ||
| static void resumeStringLike(StyleContext &sc, int quote, bool triple, bool allow_interp, bool full_highlight) {
 | ||
|     int stylePrev = sc.state;
 | ||
|     bool checkcurrent = false;
 | ||
| 
 | ||
|     // Escape characters
 | ||
|     if (sc.ch == '\\') {
 | ||
|         if (sc.chNext == quote || sc.chNext == '\\' || sc.chNext == '$') {
 | ||
|             sc.Forward();
 | ||
|         }
 | ||
|     } else if (allow_interp && sc.ch == '$') {
 | ||
|         // If the interpolation is only of a variable, do not change state
 | ||
|         if (sc.chNext == '(') {
 | ||
|             if (full_highlight) {
 | ||
|                 sc.SetState(SCE_JULIA_STRINGINTERP);
 | ||
|             } else {
 | ||
|                 sc.ForwardSetState(SCE_JULIA_STRINGINTERP);
 | ||
|             }
 | ||
|             ScanParenInterpolation(sc);
 | ||
|             sc.ForwardSetState(stylePrev);
 | ||
| 
 | ||
|             checkcurrent = true;
 | ||
| 
 | ||
|         } else if (full_highlight && IsIdentifierFirstCharacter(sc.chNext)) {
 | ||
|             sc.SetState(SCE_JULIA_STRINGINTERP);
 | ||
|             sc.Forward();
 | ||
|             sc.Forward();
 | ||
|             for (; sc.More(); sc.Forward()) {
 | ||
|                 if (! IsIdentifierCharacter(sc.ch)) {
 | ||
|                     break;
 | ||
|                 }
 | ||
|             }
 | ||
|             sc.SetState(stylePrev);
 | ||
| 
 | ||
|             checkcurrent = true;
 | ||
|         }
 | ||
| 
 | ||
|         if (checkcurrent) {
 | ||
|             // Check that the current character is not a special char,
 | ||
|             // otherwise it will be skipped
 | ||
|             resumeStringLike(sc, quote, triple, allow_interp, full_highlight);
 | ||
|         }
 | ||
| 
 | ||
|     } else if (sc.ch == quote) {
 | ||
|         if (triple) {
 | ||
|             if (sc.chNext == quote && sc.GetRelativeCharacter(2) == quote) {
 | ||
|                 // Move to the end of the triple quotes
 | ||
|                 Sci_PositionU nextIndex = sc.currentPos + 2;
 | ||
|                 while (nextIndex > sc.currentPos && sc.More()) {
 | ||
|                     sc.Forward();
 | ||
|                 }
 | ||
|                 sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|             }
 | ||
|         } else {
 | ||
|             sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static void resumeCommand(StyleContext &sc, bool triple, bool allow_interp) {
 | ||
|     return resumeStringLike(sc, '`', triple, allow_interp, true);
 | ||
| }
 | ||
| 
 | ||
| static void resumeString(StyleContext &sc, bool triple, bool allow_interp) {
 | ||
|     return resumeStringLike(sc, '"', triple, allow_interp, true);
 | ||
| }
 | ||
| 
 | ||
| static void resumeNumber (StyleContext &sc, int base, bool &with_dot, bool lexerror) {
 | ||
|     if (IsNumberExpon(sc.ch, base)) {
 | ||
|         if (IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-') {
 | ||
|             sc.Forward();
 | ||
|             // Capture all digits
 | ||
|             ScanDigits(sc, 10, false);
 | ||
|             sc.Forward();
 | ||
|         }
 | ||
|         sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|     } else if (sc.ch == '.' && sc.chNext == '.') {
 | ||
|         // Interval operator `..`
 | ||
|         sc.SetState(SCE_JULIA_OPERATOR);
 | ||
|         sc.Forward();
 | ||
|         sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|     } else if (sc.ch == '.' && !with_dot) {
 | ||
|         with_dot = true;
 | ||
|         ScanDigits(sc, base, true);
 | ||
|     } else if (IsADigit(sc.ch, base) || sc.ch == '_') {
 | ||
|         ScanDigits(sc, base, true);
 | ||
|     } else if (IsADigit(sc.ch) && !IsADigit(sc.ch, base)) {
 | ||
|         if (lexerror) {
 | ||
|             sc.ChangeState(SCE_JULIA_LEXERROR);
 | ||
|         }
 | ||
|         ScanDigits(sc, 10, false);
 | ||
|         sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|     } else {
 | ||
|         sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| static void resumeOperator (StyleContext &sc) {
 | ||
|     if (sc.chNext == ':' && (sc.ch == ':' || sc.ch == '<' ||
 | ||
|                     (sc.ch == '>' && (sc.chPrev != '-' && sc.chPrev != '=')))) {
 | ||
|         // Case `:a=>:b`
 | ||
|         sc.Forward();
 | ||
|         sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|     } else if (sc.ch == ':') {
 | ||
|         // Case `foo(:baz,:baz)` or `:one+:two`
 | ||
|         // Let the default case switch decide if it is a symbol
 | ||
|         sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|     } else if (sc.ch == '\'') {
 | ||
|         sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|     } else if ((sc.ch == '.' && sc.chPrev != '.') || IsIdentifierFirstCharacter(sc.ch) ||
 | ||
|                (! (sc.chPrev == '.' && IsOperatorFirstCharacter(sc.ch)) &&
 | ||
|                 ! IsOperatorCharacter(sc.ch)) ) {
 | ||
|         sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| void SCI_METHOD LexerJulia::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
 | ||
| 	PropSetSimple props;
 | ||
| 	Accessor styler(pAccess, &props);
 | ||
| 
 | ||
| 	Sci_Position pos = startPos;
 | ||
| 	styler.StartAt(pos);
 | ||
| 	styler.StartSegment(pos);
 | ||
| 
 | ||
|     // use the line state of each line to store block/multiline states
 | ||
|     Sci_Position curLine = styler.GetLine(startPos);
 | ||
|     // Default is false for everything and 0 counters.
 | ||
| 	int lineState = (curLine > 0) ? styler.GetLineState(curLine-1) : 0;
 | ||
| 
 | ||
|     bool transpose = (lineState >> 0) & 0x01;                // 1 bit to know if ' is allowed to mean transpose
 | ||
|     bool istripledocstring = (lineState >> 1) & 0x01;        // 1 bit to know if we are in a triple doublequotes string
 | ||
| 	bool triple_backtick = (lineState >> 2) & 0x01;          // 1 bit to know if we are in a triple backtick command
 | ||
| 	bool israwstring = (lineState >> 3) & 0x01;              // 1 bit to know if we are in a raw string
 | ||
|     int indexing_level = (int)((lineState >> 4) & 0x0F);     // 4 bits of bracket nesting counter
 | ||
|     int list_comprehension = (int)((lineState >> 8) & 0x0F); // 4 bits of parenthesis nesting counter
 | ||
|     int commentDepth = (int)((lineState >> 12) & 0x0F);      // 4 bits of nested comment counter
 | ||
| 
 | ||
|     // base for parsing number
 | ||
|     int base = 10;
 | ||
|     // number has a float dot ?
 | ||
|     bool with_dot = false;
 | ||
| 
 | ||
|     StyleContext sc(startPos, length, initStyle, styler);
 | ||
| 
 | ||
|     for (; sc.More(); sc.Forward()) {
 | ||
| 
 | ||
|         //// check for end of states
 | ||
|         switch (sc.state) {
 | ||
|             case SCE_JULIA_BRACKET:
 | ||
|                 sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|                 break;
 | ||
|             case SCE_JULIA_OPERATOR:
 | ||
|                 resumeOperator(sc);
 | ||
|                 break;
 | ||
|             case SCE_JULIA_TYPEOPERATOR:
 | ||
|                 sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|                 break;
 | ||
|             case SCE_JULIA_TYPEANNOT:
 | ||
|                 if (! IsIdentifierCharacter(sc.ch)) {
 | ||
|                     sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|                 }
 | ||
|                 break;
 | ||
|             case SCE_JULIA_IDENTIFIER:
 | ||
|                 // String literal
 | ||
|                 if (sc.ch == '\"') {
 | ||
|                     // If the string literal has a prefix, interpolation is disabled
 | ||
|                     israwstring = true;
 | ||
|                     sc.ChangeState(SCE_JULIA_STRINGLITERAL);
 | ||
|                     sc.SetState(SCE_JULIA_DEFAULT);
 | ||
| 
 | ||
|                 } else if (sc.ch == '`') {
 | ||
|                     // If the string literal has a prefix, interpolation is disabled
 | ||
|                     israwstring = true;
 | ||
|                     sc.ChangeState(SCE_JULIA_COMMANDLITERAL);
 | ||
|                     sc.SetState(SCE_JULIA_DEFAULT);
 | ||
| 
 | ||
|                 // Continue if the character is an identifier character
 | ||
|                 } else if (! IsIdentifierCharacter(sc.ch)) {
 | ||
|                     char s[MAX_JULIA_IDENT_CHARS + 1];
 | ||
|                     sc.GetCurrent(s, sizeof(s));
 | ||
| 
 | ||
|                     // Treat the keywords differently if we are indexing or not
 | ||
|                     if ( indexing_level > 0 && CheckBoundsIndexing(s)) {
 | ||
|                         // Inside [], (), `begin` and `end` are numbers not block keywords
 | ||
|                         sc.ChangeState(SCE_JULIA_NUMBER);
 | ||
|                         transpose = false;
 | ||
| 
 | ||
|                     } else {
 | ||
|                         if (keywords.InList(s)) {
 | ||
|                             sc.ChangeState(SCE_JULIA_KEYWORD1);
 | ||
|                             transpose = false;
 | ||
|                         } else if (identifiers2.InList(s)) {
 | ||
|                             sc.ChangeState(SCE_JULIA_KEYWORD2);
 | ||
|                             transpose = false;
 | ||
|                         } else if (identifiers3.InList(s)) {
 | ||
|                             sc.ChangeState(SCE_JULIA_KEYWORD3);
 | ||
|                             transpose = false;
 | ||
|                         } else if (identifiers4.InList(s)) {
 | ||
|                             sc.ChangeState(SCE_JULIA_KEYWORD4);
 | ||
|                             // These identifiers can be used for variable names also,
 | ||
|                             // so transpose is not forbidden.
 | ||
|                             //transpose = false;
 | ||
|                         }
 | ||
|                     }
 | ||
|                     sc.SetState(SCE_JULIA_DEFAULT);
 | ||
| 
 | ||
|                     // TODO: recognize begin-end blocks inside list comprehension
 | ||
|                     // b = [(begin n%2; n*2 end) for n in 1:10]
 | ||
|                     // TODO: recognize better comprehension for-if to avoid problem with code-folding
 | ||
|                     // c = [(if isempty(a); missing else first(b) end) for (a, b) in zip(l1, l2)]
 | ||
|                 }
 | ||
|                 break;
 | ||
|             case SCE_JULIA_NUMBER:
 | ||
|                 resumeNumber(sc, base, with_dot, options.highlightLexerror);
 | ||
|                 break;
 | ||
|             case SCE_JULIA_CHAR:
 | ||
|                 resumeCharacter(sc, options.highlightLexerror);
 | ||
|                 break;
 | ||
|             case SCE_JULIA_DOCSTRING:
 | ||
|                 resumeString(sc, true, !israwstring);
 | ||
|                 if (sc.state == SCE_JULIA_DEFAULT && israwstring) {
 | ||
|                     israwstring = false;
 | ||
|                 }
 | ||
|                 break;
 | ||
|             case SCE_JULIA_STRING:
 | ||
|                 resumeString(sc, false, !israwstring);
 | ||
|                 if (sc.state == SCE_JULIA_DEFAULT && israwstring) {
 | ||
|                     israwstring = false;
 | ||
|                 }
 | ||
|                 break;
 | ||
|             case SCE_JULIA_COMMAND:
 | ||
|                 resumeCommand(sc, triple_backtick, !israwstring);
 | ||
|                 break;
 | ||
|             case SCE_JULIA_MACRO:
 | ||
|                 if (IsASpace(sc.ch) || ! IsIdentifierCharacter(sc.ch)) {
 | ||
|                     sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|                 }
 | ||
|                 break;
 | ||
|             case SCE_JULIA_SYMBOL:
 | ||
|                 if (! IsIdentifierCharacter(sc.ch)) {
 | ||
|                     sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|                 }
 | ||
|                 break;
 | ||
|             case SCE_JULIA_COMMENT:
 | ||
|                 if( commentDepth > 0 ) {
 | ||
|                     // end or start of a nested a block comment
 | ||
|                     if ( sc.ch == '=' && sc.chNext == '#') {
 | ||
|                         commentDepth --;
 | ||
|                         sc.Forward();
 | ||
| 
 | ||
|                         if (commentDepth == 0) {
 | ||
|                             sc.ForwardSetState(SCE_JULIA_DEFAULT);
 | ||
|                         }
 | ||
|                     } else if( sc.ch == '#' && sc.chNext == '=') {
 | ||
|                         commentDepth ++;
 | ||
|                         sc.Forward();
 | ||
|                     }
 | ||
|                 } else {
 | ||
|                     // single line comment
 | ||
|                     if (sc.atLineEnd || sc.ch == '\r' || sc.ch == '\n') {
 | ||
|                         sc.SetState(SCE_JULIA_DEFAULT);
 | ||
|                         transpose = false;
 | ||
|                     }
 | ||
|                 }
 | ||
|                 break;
 | ||
|         }
 | ||
| 
 | ||
|         // check start of a new state
 | ||
|         if (sc.state == SCE_JULIA_DEFAULT) {
 | ||
|             if (sc.ch == '#') {
 | ||
|                 sc.SetState(SCE_JULIA_COMMENT);
 | ||
|                 // increment depth if we are a block comment
 | ||
|                 if(sc.chNext == '=') {
 | ||
|                     commentDepth ++;
 | ||
|                     sc.Forward();
 | ||
|                 }
 | ||
|             } else if (sc.ch == '!') {
 | ||
|                 sc.SetState(SCE_JULIA_OPERATOR);
 | ||
|                 transpose = false;
 | ||
|             } else if (sc.ch == '\'') {
 | ||
|                 if (transpose) {
 | ||
|                     sc.SetState(SCE_JULIA_OPERATOR);
 | ||
|                 } else {
 | ||
|                     sc.SetState(SCE_JULIA_CHAR);
 | ||
|                 }
 | ||
|             } else if (sc.ch == '\"') {
 | ||
|                 istripledocstring = (sc.chNext == '\"' && sc.GetRelativeCharacter(2) == '\"');
 | ||
|                 if (istripledocstring) {
 | ||
|                     sc.SetState(SCE_JULIA_DOCSTRING);
 | ||
|                     // Move to the end of the triple quotes
 | ||
|                     Sci_PositionU nextIndex = sc.currentPos + 2;
 | ||
|                     while (nextIndex > sc.currentPos && sc.More()) {
 | ||
|                         sc.Forward();
 | ||
|                     }
 | ||
|                 } else {
 | ||
|                     sc.SetState(SCE_JULIA_STRING);
 | ||
|                 }
 | ||
|             } else if (sc.ch == '`') {
 | ||
|                 triple_backtick = (sc.chNext == '`' && sc.GetRelativeCharacter(2) == '`');
 | ||
|                 sc.SetState(SCE_JULIA_COMMAND);
 | ||
|                 if (triple_backtick) {
 | ||
|                     // Move to the end of the triple backticks
 | ||
|                     Sci_PositionU nextIndex = sc.currentPos + 2;
 | ||
|                     while (nextIndex > sc.currentPos && sc.More()) {
 | ||
|                         sc.Forward();
 | ||
|                     }
 | ||
|                 }
 | ||
|             } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
 | ||
|                 initNumber(sc, base, with_dot);
 | ||
|             } else if (IsIdentifierFirstCharacter(sc.ch)) {
 | ||
|                 sc.SetState(SCE_JULIA_IDENTIFIER);
 | ||
|                 transpose = true;
 | ||
|             } else if (sc.ch == '@') {
 | ||
|                 sc.SetState(SCE_JULIA_MACRO);
 | ||
|                 transpose = false;
 | ||
| 
 | ||
|             // Several parsing of operators, should keep the order of `if` blocks
 | ||
|             } else if ((sc.ch == ':' || sc.ch == '<' || sc.ch == '>') && sc.chNext == ':') {
 | ||
|                 sc.SetState(SCE_JULIA_TYPEOPERATOR);
 | ||
|                 sc.Forward();
 | ||
|                 // Highlight the next identifier, if option is set
 | ||
|                 if (options.highlightTypeannotation &&
 | ||
|                     IsIdentifierFirstCharacter(sc.chNext)) {
 | ||
|                     sc.ForwardSetState(SCE_JULIA_TYPEANNOT);
 | ||
|                 }
 | ||
|             } else if (sc.ch == ':') {
 | ||
|                 // TODO: improve detection of range
 | ||
|                 // should be solved with begin-end parsing
 | ||
|                 // `push!(arr, s1 :s2)` and `a[begin :end]
 | ||
|                 if (IsIdentifierFirstCharacter(sc.chNext) &&
 | ||
|                     ! IsIdentifierCharacter(sc.chPrev) &&
 | ||
|                     sc.chPrev != ')' && sc.chPrev != ']' ) {
 | ||
|                     sc.SetState(SCE_JULIA_SYMBOL);
 | ||
|                 } else {
 | ||
|                     sc.SetState(SCE_JULIA_OPERATOR);
 | ||
|                 }
 | ||
|             } else if (IsJuliaParen(sc.ch)) {
 | ||
|                 if (sc.ch == '[') {
 | ||
|                     list_comprehension ++;
 | ||
|                     indexing_level ++;
 | ||
|                 } else if (sc.ch == ']' && (indexing_level > 0)) {
 | ||
|                     list_comprehension --;
 | ||
|                     indexing_level --;
 | ||
|                 } else if (sc.ch == '(') {
 | ||
|                     list_comprehension ++;
 | ||
|                 } else if (sc.ch == ')' && (list_comprehension > 0)) {
 | ||
|                     list_comprehension --;
 | ||
|                 }
 | ||
| 
 | ||
|                 if (sc.ch == ')' || sc.ch == ']' || sc.ch == '}') {
 | ||
|                     transpose = true;
 | ||
|                 } else {
 | ||
|                     transpose = false;
 | ||
|                 }
 | ||
|                 sc.SetState(SCE_JULIA_BRACKET);
 | ||
|             } else if (IsOperatorFirstCharacter(sc.ch)) {
 | ||
|                 transpose = false;
 | ||
|                 sc.SetState(SCE_JULIA_OPERATOR);
 | ||
|             } else {
 | ||
|                 transpose = false;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         // update the line information (used for line-by-line lexing and folding)
 | ||
|         if (sc.atLineEnd) {
 | ||
|             // set the line state to the current state
 | ||
|             curLine = styler.GetLine(sc.currentPos);
 | ||
| 
 | ||
|             lineState = ((transpose ? 1 : 0) << 0) |
 | ||
|                         ((istripledocstring ? 1 : 0) << 1) |
 | ||
|                         ((triple_backtick ? 1 : 0) << 2) |
 | ||
|                         ((israwstring ? 1 : 0) << 3) |
 | ||
|                         ((indexing_level & 0x0F) << 4) |
 | ||
|                         ((list_comprehension & 0x0F) << 8) |
 | ||
|                         ((commentDepth & 0x0F) << 12);
 | ||
|             styler.SetLineState(curLine, lineState);
 | ||
|         }
 | ||
|     }
 | ||
|     sc.Complete();
 | ||
| }
 | ||
| 
 | ||
| void SCI_METHOD LexerJulia::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
 | ||
| 
 | ||
| 	if (!options.fold)
 | ||
| 		return;
 | ||
| 
 | ||
| 	LexAccessor styler(pAccess);
 | ||
| 
 | ||
| 	Sci_PositionU endPos = startPos + length;
 | ||
| 	int visibleChars = 0;
 | ||
| 	Sci_Position lineCurrent = styler.GetLine(startPos);
 | ||
| 	int levelCurrent = SC_FOLDLEVELBASE;
 | ||
|     int lineState = 0;
 | ||
| 	if (lineCurrent > 0) {
 | ||
| 		levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
 | ||
|         lineState = styler.GetLineState(lineCurrent-1);
 | ||
|     }
 | ||
| 
 | ||
|     // level of nested brackets
 | ||
|     int indexing_level = (int)((lineState >> 4) & 0x0F);     // 4 bits of bracket nesting counter
 | ||
|     // level of nested parenthesis or brackets
 | ||
|     int list_comprehension = (int)((lineState >> 8) & 0x0F); // 4 bits of parenthesis nesting counter
 | ||
|     //int commentDepth = (int)((lineState >> 12) & 0x0F);      // 4 bits of nested comment counter
 | ||
|     
 | ||
| 	Sci_PositionU lineStartNext = styler.LineStart(lineCurrent+1);
 | ||
| 	int levelNext = levelCurrent;
 | ||
| 	char chNext = styler[startPos];
 | ||
| 	int stylePrev = styler.StyleAt(startPos - 1);
 | ||
| 	int styleNext = styler.StyleAt(startPos);
 | ||
| 	int style = initStyle;
 | ||
|     char word[100];
 | ||
|     int wordlen = 0;
 | ||
|     for (Sci_PositionU i = startPos; i < endPos; i++) {
 | ||
| 		char ch = chNext;
 | ||
| 		chNext = styler.SafeGetCharAt(i + 1);
 | ||
| 		style = styleNext;
 | ||
| 		styleNext = styler.StyleAt(i + 1);
 | ||
| 		bool atEOL = i == (lineStartNext-1);
 | ||
| 
 | ||
|         // a start/end of comment block
 | ||
|         if (options.foldComment && style == SCE_JULIA_COMMENT) {
 | ||
|             // start of block comment
 | ||
|             if (ch == '#' && chNext == '=') {
 | ||
|                 levelNext ++;
 | ||
|             }
 | ||
|             // end of block comment
 | ||
|             if (ch == '=' && chNext == '#' && levelNext > 0) {
 | ||
|                 levelNext --;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         // Syntax based folding, accounts for list comprehension
 | ||
|         if (options.foldSyntaxBased) {
 | ||
|             // list comprehension allow `for`, `if` and `begin` without `end`
 | ||
|             if (style == SCE_JULIA_BRACKET) {
 | ||
|                 if (ch == '[') {
 | ||
|                     list_comprehension ++;
 | ||
|                     indexing_level ++;
 | ||
|                     levelNext ++;
 | ||
|                 } else if (ch == ']') {
 | ||
|                     list_comprehension --;
 | ||
|                     indexing_level --;
 | ||
|                     levelNext --;
 | ||
|                 } else if (ch == '(') {
 | ||
|                     list_comprehension ++;
 | ||
|                     levelNext ++;
 | ||
|                 } else if (ch == ')') {
 | ||
|                     list_comprehension --;
 | ||
|                     levelNext --;
 | ||
|                 }
 | ||
|                 // check non-negative
 | ||
|                 if (indexing_level < 0) {
 | ||
|                     indexing_level = 0;
 | ||
|                 }
 | ||
|                 if (list_comprehension < 0) {
 | ||
|                     list_comprehension = 0;
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             // keyword
 | ||
|             if (style == SCE_JULIA_KEYWORD1) {
 | ||
|                 word[wordlen++] = static_cast<char>(ch);
 | ||
|                 if (wordlen == 100) {  // prevent overflow
 | ||
|                     word[0] = '\0';
 | ||
|                     wordlen = 1;
 | ||
|                 }
 | ||
|                 if (styleNext != SCE_JULIA_KEYWORD1) {
 | ||
|                     word[wordlen] = '\0';
 | ||
|                     wordlen = 0;
 | ||
|                     if (list_comprehension <= 0 && indexing_level <= 0) {
 | ||
|                         levelNext += CheckKeywordFoldPoint(word);
 | ||
|                     }
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         // Docstring
 | ||
|         if (options.foldDocstring) {
 | ||
|             if (stylePrev != SCE_JULIA_DOCSTRING && style == SCE_JULIA_DOCSTRING) {
 | ||
|                 levelNext ++;
 | ||
|             } else if (style == SCE_JULIA_DOCSTRING && styleNext != SCE_JULIA_DOCSTRING) {
 | ||
|                 levelNext --;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         // check non-negative level
 | ||
|         if (levelNext < 0) {
 | ||
|             levelNext = 0;
 | ||
|         }
 | ||
| 
 | ||
|         if (!IsASpace(ch)) {
 | ||
|             visibleChars++;
 | ||
|         }
 | ||
|         stylePrev = style;
 | ||
| 
 | ||
|         if (atEOL || (i == endPos-1)) {
 | ||
|             int levelUse = levelCurrent;
 | ||
|             int lev = levelUse | levelNext << 16;
 | ||
|             if (visibleChars == 0 && options.foldCompact) {
 | ||
|                 lev |= SC_FOLDLEVELWHITEFLAG;
 | ||
|             }
 | ||
|             if (levelUse < levelNext) {
 | ||
|                 lev |= SC_FOLDLEVELHEADERFLAG;
 | ||
|             }
 | ||
|             if (lev != styler.LevelAt(lineCurrent)) {
 | ||
|                 styler.SetLevel(lineCurrent, lev);
 | ||
|             }
 | ||
|             lineCurrent++;
 | ||
|             lineStartNext = styler.LineStart(lineCurrent+1);
 | ||
|             levelCurrent = levelNext;
 | ||
|             if (atEOL && (i == static_cast<Sci_PositionU>(styler.Length() - 1))) {
 | ||
|                 // There is an empty line at end of file so give it same level and empty
 | ||
|                 styler.SetLevel(lineCurrent, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG);
 | ||
|             }
 | ||
|             visibleChars = 0;
 | ||
|         }
 | ||
|     }
 | ||
| }
 | ||
| 
 | ||
| LexerModule lmJulia(SCLEX_JULIA, LexerJulia::LexerFactoryJulia, "julia", juliaWordLists);
 |