diff --git a/doc/LexillaHistory.html b/doc/LexillaHistory.html index a4c2f61c..6e786b4b 100644 --- a/doc/LexillaHistory.html +++ b/doc/LexillaHistory.html @@ -615,6 +615,10 @@

Smalltalk: Fix scaled decimal numbers without decimal separator. Pull request #274. +
  • + Lexer added for Zig "zig". + Pull request #267. +
  • Release 5.4.0 diff --git a/include/LexicalStyles.iface b/include/LexicalStyles.iface index 05d0e660..47a389ba 100644 --- a/include/LexicalStyles.iface +++ b/include/LexicalStyles.iface @@ -147,6 +147,7 @@ val SCLEX_GDSCRIPT=135 val SCLEX_TOML=136 val SCLEX_TROFF=137 val SCLEX_DART=138 +val SCLEX_ZIG=139 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -2389,3 +2390,22 @@ val SCE_DART_KW_PRIMARY=23 val SCE_DART_KW_SECONDARY=24 val SCE_DART_KW_TERTIARY=25 val SCE_DART_KW_TYPE=26 +# Lexical states for SCLEX_ZIG +lex Zig=SCLEX_ZIG SCE_ZIG_ +val SCE_ZIG_DEFAULT=0 +val SCE_ZIG_COMMENTLINE=1 +val SCE_ZIG_COMMENTLINEDOC=2 +val SCE_ZIG_COMMENTLINETOP=3 +val SCE_ZIG_NUMBER=4 +val SCE_ZIG_OPERATOR=5 +val SCE_ZIG_CHARACTER=6 +val SCE_ZIG_STRING=7 +val SCE_ZIG_MULTISTRING=8 +val SCE_ZIG_ESCAPECHAR=9 +val SCE_ZIG_IDENTIFIER=10 +val SCE_ZIG_FUNCTION=11 +val SCE_ZIG_BUILTIN_FUNCTION=12 +val SCE_ZIG_KW_PRIMARY=13 +val SCE_ZIG_KW_SECONDARY=14 +val SCE_ZIG_KW_TERTIARY=15 +val SCE_ZIG_KW_TYPE=16 diff --git a/include/SciLexer.h b/include/SciLexer.h index 1b1ebd86..7bacb878 100644 --- a/include/SciLexer.h +++ b/include/SciLexer.h @@ -151,6 +151,7 @@ #define SCLEX_TOML 136 #define SCLEX_TROFF 137 #define SCLEX_DART 138 +#define SCLEX_ZIG 139 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 @@ -2131,6 +2132,23 @@ #define SCE_DART_KW_SECONDARY 24 #define SCE_DART_KW_TERTIARY 25 #define SCE_DART_KW_TYPE 26 +#define SCE_ZIG_DEFAULT 0 +#define SCE_ZIG_COMMENTLINE 1 +#define SCE_ZIG_COMMENTLINEDOC 2 +#define SCE_ZIG_COMMENTLINETOP 3 +#define SCE_ZIG_NUMBER 4 +#define SCE_ZIG_OPERATOR 5 +#define SCE_ZIG_CHARACTER 6 +#define SCE_ZIG_STRING 7 +#define SCE_ZIG_MULTISTRING 8 +#define SCE_ZIG_ESCAPECHAR 9 +#define SCE_ZIG_IDENTIFIER 10 +#define SCE_ZIG_FUNCTION 11 +#define SCE_ZIG_BUILTIN_FUNCTION 12 +#define SCE_ZIG_KW_PRIMARY 13 +#define SCE_ZIG_KW_SECONDARY 14 +#define SCE_ZIG_KW_TERTIARY 15 +#define SCE_ZIG_KW_TYPE 16 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif diff --git a/lexers/LexZig.cxx b/lexers/LexZig.cxx new file mode 100644 index 00000000..b262fee2 --- /dev/null +++ b/lexers/LexZig.cxx @@ -0,0 +1,465 @@ +// Scintilla source code edit control +/** @file LexZig.cxx + ** Lexer for Zig language. + **/ +// Based on Zufu Liu's Notepad4 Zig lexer +// Modified for Scintilla by Jiri Techet, 2024 +// The License.txt file describes the conditions under which this software may be distributed. + +#include +#include + +#include +#include +#include +#include +#include + +#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" +#include "OptionSet.h" +#include "DefaultLexer.h" + +using namespace Scintilla; +using namespace Lexilla; + +namespace { +// Use an unnamed namespace to protect the functions and classes from name conflicts + +constexpr bool IsAGraphic(int ch) noexcept { + // excludes C0 control characters and whitespace + return ch > 32 && ch < 127; +} + +constexpr bool IsIdentifierStart(int ch) noexcept { + return IsUpperOrLowerCase(ch) || ch == '_'; +} + +constexpr bool IsIdentifierStartEx(int ch) noexcept { + return IsIdentifierStart(ch) || ch >= 0x80; +} + +constexpr bool IsNumberStart(int ch, int chNext) noexcept { + return IsADigit(ch) || (ch == '.' && IsADigit(chNext)); +} + +constexpr bool IsIdentifierChar(int ch) noexcept { + return IsAlphaNumeric(ch) || ch == '_'; +} + +constexpr bool IsNumberContinue(int chPrev, int ch, int chNext) noexcept { + return ((ch == '+' || ch == '-') && (chPrev == 'e' || chPrev == 'E')) + || (ch == '.' && chNext != '.'); +} + +constexpr bool IsDecimalNumber(int chPrev, int ch, int chNext) noexcept { + return IsIdentifierChar(ch) || IsNumberContinue(chPrev, ch, chNext); +} + +constexpr bool IsIdentifierCharEx(int ch) noexcept { + return IsIdentifierChar(ch) || ch >= 0x80; +} + +// https://ziglang.org/documentation/master/#Escape-Sequences +struct EscapeSequence { + int outerState = SCE_ZIG_DEFAULT; + int digitsLeft = 0; + bool brace = false; + + // highlight any character as escape sequence. + void resetEscapeState(int state, int chNext) noexcept { + outerState = state; + digitsLeft = 1; + brace = false; + if (chNext == 'x') { + digitsLeft = 3; + } else if (chNext == 'u') { + digitsLeft = 5; + } + } + void resetEscapeState(int state) noexcept { + outerState = state; + digitsLeft = 1; + brace = false; + } + bool atEscapeEnd(int ch) noexcept { + --digitsLeft; + return digitsLeft <= 0 || !IsAHeXDigit(ch); + } +}; + +enum { + ZigLineStateMaskLineComment = 1, // line comment + ZigLineStateMaskMultilineString = 1 << 1, // multiline string +}; + +struct FoldLineState { + int lineComment; + int multilineString; + constexpr explicit FoldLineState(int lineState) noexcept: + lineComment(lineState & ZigLineStateMaskLineComment), + multilineString((lineState >> 1) & 1) { + } +}; + +enum class KeywordType { + None = SCE_ZIG_DEFAULT, + Function = SCE_ZIG_FUNCTION, +}; + +enum { + KeywordIndex_Primary = 0, + KeywordIndex_Secondary = 1, + KeywordIndex_Tertiary = 2, + KeywordIndex_Type = 3, +}; + +// Options used for LexerZig +struct OptionsZig { + bool fold = false; +}; + +const char *const zigWordListDesc[] = { + "Primary keywords", + "Secondary keywords", + "Tertiary keywords", + "Global type definitions", + nullptr +}; + +struct OptionSetZig : public OptionSet { + OptionSetZig() { + DefineProperty("fold", &OptionsZig::fold); + + DefineWordListSets(zigWordListDesc); + } +}; + +LexicalClass lexicalClasses[] = { + // Lexer ZIG SCLEX_ZIG SCE_ZIG_: + 0, "SCE_ZIG_DEFAULT", "default", "White space", + 1, "SCE_ZIG_COMMENTLINE", "comment line", "Comment: //", + 2, "SCE_ZIG_COMMENTLINEDOC", "comment line documentation", "Comment: ///", + 3, "SCE_ZIG_COMMENTLINETOP", "comment line documentation", "Comment: //!", + 4, "SCE_ZIG_NUMBER", "literal numeric", "Number", + 5, "SCE_ZIG_OPERATOR", "operator", "Operator", + 6, "SCE_ZIG_CHARACTER", "literal string character", "Single quoted string", + 7, "SCE_ZIG_STRING", "literal string", "Double quoted string", + 8, "SCE_ZIG_MULTISTRING", "literal string multiline", "Multiline string introduced by two backslashes", + 9, "SCE_ZIG_ESCAPECHAR", "literal string escapesequence", "Escape sequence", + 10, "SCE_ZIG_IDENTIFIER", "identifier", "Identifier", + 11, "SCE_ZIG_FUNCTION", "identifier", "Function definition", + 12, "SCE_ZIG_BUILTIN_FUNCTION", "identifier", "Builtin function", + 13, "SCE_ZIG_KW_PRIMARY", "keyword", "Primary keywords", + 14, "SCE_ZIG_KW_SECONDARY", "identifier", "Secondary keywords", + 15, "SCE_ZIG_KW_TERTIARY", "identifier", "Tertiary keywords", + 16, "SCE_ZIG_KW_TYPE", "identifier", "Global types", +}; + +class LexerZig : public DefaultLexer { + WordList keywordsPrimary; + WordList keywordsSecondary; + WordList keywordsTertiary; + WordList keywordsTypes; + OptionsZig options; + OptionSetZig osZig; +public: + LexerZig(const char *languageName_, int language_) : + DefaultLexer(languageName_, language_, lexicalClasses, std::size(lexicalClasses)) { + } + // Deleted so LexerZig objects can not be copied. + LexerZig(const LexerZig &) = delete; + LexerZig(LexerZig &&) = delete; + void operator=(const LexerZig &) = delete; + void operator=(LexerZig &&) = delete; + ~LexerZig() override = default; + + void SCI_METHOD Release() override { + delete this; + } + int SCI_METHOD Version() const override { + return lvRelease5; + } + const char *SCI_METHOD PropertyNames() override { + return osZig.PropertyNames(); + } + int SCI_METHOD PropertyType(const char *name) override { + return osZig.PropertyType(name); + } + const char *SCI_METHOD DescribeProperty(const char *name) override { + return osZig.DescribeProperty(name); + } + Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override; + const char *SCI_METHOD PropertyGet(const char *key) override { + return osZig.PropertyGet(key); + } + const char *SCI_METHOD DescribeWordListSets() override { + return osZig.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 nullptr; + } + + void BacktrackToStart(const LexAccessor &styler, int stateMask, Sci_PositionU &startPos, Sci_Position &lengthDoc, int &initStyle); + Sci_PositionU LookbackNonWhite(LexAccessor &styler, Sci_PositionU startPos, int &chPrevNonWhite, int &stylePrevNonWhite); + + static ILexer5 *LexerFactoryZig() { + return new LexerZig("zig", SCLEX_ZIG); + } +}; + +Sci_Position SCI_METHOD LexerZig::PropertySet(const char *key, const char *val) { + if (osZig.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +Sci_Position SCI_METHOD LexerZig::WordListSet(int n, const char *wl) { + WordList *wordListN = nullptr; + switch (n) { + case 0: + wordListN = &keywordsPrimary; + break; + case 1: + wordListN = &keywordsSecondary; + break; + case 2: + wordListN = &keywordsTertiary; + break; + case 3: + wordListN = &keywordsTypes; + break; + default: + break; + } + Sci_Position firstModification = -1; + if (wordListN && wordListN->Set(wl, false)) { + firstModification = 0; + } + return firstModification; +} + +void LexerZig::Lex(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) { + Accessor styler(pAccess, nullptr); + + KeywordType kwType = KeywordType::None; + int visibleChars = 0; + int lineState = 0; + EscapeSequence escSeq; + + StyleContext sc(startPos, lengthDoc, initStyle, styler); + + while (sc.More()) { + switch (sc.state) { + case SCE_ZIG_OPERATOR: + sc.SetState(SCE_ZIG_DEFAULT); + break; + + case SCE_ZIG_NUMBER: + if (!IsDecimalNumber(sc.chPrev, sc.ch, sc.chNext)) { + sc.SetState(SCE_ZIG_DEFAULT); + } + break; + + case SCE_ZIG_IDENTIFIER: + case SCE_ZIG_BUILTIN_FUNCTION: + if (!IsIdentifierCharEx(sc.ch)) { + if (sc.state == SCE_ZIG_IDENTIFIER) { + char s[64]; + sc.GetCurrent(s, sizeof(s)); + if (kwType != KeywordType::None) { + sc.ChangeState(static_cast(kwType)); + } else if (keywordsPrimary.InList(s)) { + sc.ChangeState(SCE_ZIG_KW_PRIMARY); + kwType = KeywordType::None; + if (strcmp(s, "fn") == 0) { + kwType = KeywordType::Function; + } + } else if (keywordsSecondary.InList(s)) { + sc.ChangeState(SCE_ZIG_KW_SECONDARY); + } else if (keywordsTertiary.InList(s)) { + sc.ChangeState(SCE_ZIG_KW_TERTIARY); + } else if (keywordsTypes.InList(s)) { + sc.ChangeState(SCE_ZIG_KW_TYPE); + } + } + if (sc.state != SCE_ZIG_KW_PRIMARY) { + kwType = KeywordType::None; + } + sc.SetState(SCE_ZIG_DEFAULT); + } + break; + + case SCE_ZIG_CHARACTER: + case SCE_ZIG_STRING: + case SCE_ZIG_MULTISTRING: + if (sc.atLineStart) { + sc.SetState(SCE_ZIG_DEFAULT); + } else if (sc.ch == '\\' && sc.state != SCE_ZIG_MULTISTRING) { + escSeq.resetEscapeState(sc.state, sc.chNext); + sc.SetState(SCE_ZIG_ESCAPECHAR); + sc.Forward(); + if (sc.Match('u', '{')) { + escSeq.brace = true; + escSeq.digitsLeft = 9; + sc.Forward(); + } + } else if ((sc.ch == '\'' && sc.state == SCE_ZIG_CHARACTER) || (sc.ch == '\"' && sc.state == SCE_ZIG_STRING)) { + sc.ForwardSetState(SCE_ZIG_DEFAULT); + } else if (sc.state != SCE_ZIG_CHARACTER) { + if (sc.ch == '{' || sc.ch == '}') { + if (sc.ch == sc.chNext) { + escSeq.resetEscapeState(sc.state); + sc.SetState(SCE_ZIG_ESCAPECHAR); + sc.Forward(); + } + } + } + break; + + case SCE_ZIG_ESCAPECHAR: + if (escSeq.atEscapeEnd(sc.ch)) { + if (escSeq.brace && sc.ch == '}') { + sc.Forward(); + } + sc.SetState(escSeq.outerState); + continue; + } + break; + + case SCE_ZIG_COMMENTLINE: + case SCE_ZIG_COMMENTLINEDOC: + case SCE_ZIG_COMMENTLINETOP: + if (sc.atLineStart) { + sc.SetState(SCE_ZIG_DEFAULT); + } + break; + } + + if (sc.state == SCE_ZIG_DEFAULT) { + if (sc.Match('/', '/')) { + if (visibleChars == 0) { + lineState = ZigLineStateMaskLineComment; + } + sc.SetState(SCE_ZIG_COMMENTLINE); + sc.Forward(2); + if (sc.ch == '!') { + sc.ChangeState(SCE_ZIG_COMMENTLINETOP); + } else if (sc.ch == '/' && sc.chNext != '/') { + sc.ChangeState(SCE_ZIG_COMMENTLINEDOC); + } + } else if (sc.Match('\\', '\\')) { + lineState = ZigLineStateMaskMultilineString; + sc.SetState(SCE_ZIG_MULTISTRING); + } else if (sc.ch == '\"') { + sc.SetState(SCE_ZIG_STRING); + } else if (sc.ch == '\'') { + sc.SetState(SCE_ZIG_CHARACTER); + } else if (IsNumberStart(sc.ch, sc.chNext)) { + sc.SetState(SCE_ZIG_NUMBER); + } else if ((sc.ch == '@' && IsIdentifierStartEx(sc.chNext)) || IsIdentifierStartEx(sc.ch)) { + sc.SetState((sc.ch == '@') ? SCE_ZIG_BUILTIN_FUNCTION : SCE_ZIG_IDENTIFIER); + } else if (IsAGraphic(sc.ch)) { + sc.SetState(SCE_ZIG_OPERATOR); + } + } + + if (visibleChars == 0 && !isspacechar(sc.ch)) { + visibleChars++; + } + if (sc.atLineEnd) { + styler.SetLineState(sc.currentLine, lineState); + lineState = 0; + kwType = KeywordType::None; + visibleChars = 0; + } + sc.Forward(); + } + + sc.Complete(); +} + +void LexerZig::Fold(Sci_PositionU startPos, Sci_Position lengthDoc, int initStyle, IDocument *pAccess) { + if (!options.fold) + return; + + Accessor styler(pAccess, nullptr); + const Sci_PositionU endPos = startPos + lengthDoc; + Sci_Position lineCurrent = styler.GetLine(startPos); + while (lineCurrent > 0) { + lineCurrent--; + startPos = styler.LineStart(lineCurrent); + initStyle = (startPos > 0) ? styler.StyleIndexAt(startPos) : 0; + if (!AnyOf(initStyle, SCE_ZIG_MULTISTRING, + SCE_ZIG_COMMENTLINE, SCE_ZIG_COMMENTLINEDOC, SCE_ZIG_COMMENTLINETOP)) { + break; + } + } + FoldLineState foldPrev(0); + int levelCurrent = SC_FOLDLEVELBASE; + if (lineCurrent > 0) { + levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16; + foldPrev = FoldLineState(styler.GetLineState(lineCurrent - 1)); + } + + int levelNext = levelCurrent; + FoldLineState foldCurrent(styler.GetLineState(lineCurrent)); + Sci_PositionU lineStartNext = styler.LineStart(lineCurrent + 1); + lineStartNext = std::min(lineStartNext, endPos); + + while (startPos < endPos) { + initStyle = styler.StyleIndexAt(startPos); + + if (initStyle == SCE_ZIG_OPERATOR) { + const char ch = styler[startPos]; + if (ch == '{' || ch == '[' || ch == '(') { + levelNext++; + } else if (ch == '}' || ch == ']' || ch == ')') { + levelNext--; + } + } + + ++startPos; + if (startPos == lineStartNext) { + const FoldLineState foldNext(styler.GetLineState(lineCurrent + 1)); + levelNext = std::max(levelNext, SC_FOLDLEVELBASE); + if (foldCurrent.lineComment) { + levelNext += foldNext.lineComment - foldPrev.lineComment; + } else if (foldCurrent.multilineString) { + levelNext += foldNext.multilineString - foldPrev.multilineString; + } + + const int levelUse = levelCurrent; + int lev = levelUse | (levelNext << 16); + if (levelUse < levelNext) { + lev |= SC_FOLDLEVELHEADERFLAG; + } + styler.SetLevel(lineCurrent, lev); + + lineCurrent++; + lineStartNext = styler.LineStart(lineCurrent + 1); + lineStartNext = std::min(lineStartNext, endPos); + levelCurrent = levelNext; + foldPrev = foldCurrent; + foldCurrent = foldNext; + } + } +} + +} // unnamed namespace end + +extern const LexerModule lmZig(SCLEX_ZIG, LexerZig::LexerFactoryZig, "zig", zigWordListDesc); diff --git a/src/Lexilla.cxx b/src/Lexilla.cxx index 7751b107..341c5622 100644 --- a/src/Lexilla.cxx +++ b/src/Lexilla.cxx @@ -163,6 +163,7 @@ extern const LexerModule lmVisualProlog; extern const LexerModule lmX12; extern const LexerModule lmXML; extern const LexerModule lmYAML; +extern const LexerModule lmZig; //--Autogenerated -- end of automatically generated section @@ -314,6 +315,7 @@ void AddEachLexer() { &lmX12, &lmXML, &lmYAML, + &lmZig, //--Autogenerated -- end of automatically generated section }); diff --git a/src/Lexilla/Lexilla.xcodeproj/project.pbxproj b/src/Lexilla/Lexilla.xcodeproj/project.pbxproj index b3b4e12e..f5b4aa4d 100644 --- a/src/Lexilla/Lexilla.xcodeproj/project.pbxproj +++ b/src/Lexilla/Lexilla.xcodeproj/project.pbxproj @@ -159,6 +159,7 @@ 3D044C4CA34C6FD7E58E0091 /* LexTOML.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 42BC44CCB57D4E78DEE6E358 /* LexTOML.cxx */; }; 14314DCD945FDA90481F0A0D /* LexTroff.cxx in Sources */ = {isa = PBXBuildFile; fileRef = D2EF4913B8F91656C787F584 /* LexTroff.cxx */; }; 0DFB4F5F94B018794ADB389D /* LexDart.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 1F274010A7943C43BA265511 /* LexDart.cxx */; }; + CEC8496B8D9712E6EEDBC301 /* LexZig.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 71684CF6BCC80369BCE2F893 /* LexZig.cxx */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -316,6 +317,7 @@ 42BC44CCB57D4E78DEE6E358 /* LexTOML.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexTOML.cxx; path = ../../lexers/LexTOML.cxx; sourceTree = SOURCE_ROOT; }; D2EF4913B8F91656C787F584 /* LexTroff.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexTroff.cxx; path = ../../lexers/LexTroff.cxx; sourceTree = SOURCE_ROOT; }; 1F274010A7943C43BA265511 /* LexDart.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexDart.cxx; path = ../../lexers/LexDart.cxx; sourceTree = SOURCE_ROOT; }; + 71684CF6BCC80369BCE2F893 /* LexZig.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LexZig.cxx; path = ../../lexers/LexZig.cxx; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -481,6 +483,7 @@ 28BA731E24E34D9500272C2D /* LexVisualProlog.cxx */, 28BA730A24E34D9400272C2D /* LexX12.cxx */, 28BA72E724E34D9200272C2D /* LexYAML.cxx */, + 71684CF6BCC80369BCE2F893 /* LexZig.cxx */, ); name = Lexers; sourceTree = ""; @@ -741,6 +744,7 @@ 3D044C4CA34C6FD7E58E0091 /* LexTOML.cxx in Sources */, 14314DCD945FDA90481F0A0D /* LexTroff.cxx in Sources */, 0DFB4F5F94B018794ADB389D /* LexDart.cxx in Sources */, + CEC8496B8D9712E6EEDBC301 /* LexZig.cxx in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/deps.mak b/src/deps.mak index 2c47d86b..34a30249 100644 --- a/src/deps.mak +++ b/src/deps.mak @@ -1618,3 +1618,17 @@ $(DIR_O)/LexYAML.o: \ ../lexlib/StyleContext.h \ ../lexlib/CharacterSet.h \ ../lexlib/LexerModule.h +$(DIR_O)/LexZig.o: \ + ../lexers/LexZig.cxx \ + ../../scintilla/include/ILexer.h \ + ../../scintilla/include/Sci_Position.h \ + ../../scintilla/include/Scintilla.h \ + ../include/SciLexer.h \ + ../lexlib/WordList.h \ + ../lexlib/LexAccessor.h \ + ../lexlib/Accessor.h \ + ../lexlib/StyleContext.h \ + ../lexlib/CharacterSet.h \ + ../lexlib/LexerModule.h \ + ../lexlib/OptionSet.h \ + ../lexlib/DefaultLexer.h diff --git a/src/lexilla.mak b/src/lexilla.mak index fd582e05..0246787a 100644 --- a/src/lexilla.mak +++ b/src/lexilla.mak @@ -205,6 +205,7 @@ LEX_OBJS=\ $(DIR_O)\LexVisualProlog.obj \ $(DIR_O)\LexX12.obj \ $(DIR_O)\LexYAML.obj \ + $(DIR_O)\LexZig.obj \ #--Autogenerated -- end of automatically generated section diff --git a/src/nmdeps.mak b/src/nmdeps.mak index 66a5ffdb..14eaaf62 100644 --- a/src/nmdeps.mak +++ b/src/nmdeps.mak @@ -1618,3 +1618,17 @@ $(DIR_O)/LexYAML.obj: \ ../lexlib/StyleContext.h \ ../lexlib/CharacterSet.h \ ../lexlib/LexerModule.h +$(DIR_O)/LexZig.obj: \ + ../lexers/LexZig.cxx \ + ../../scintilla/include/ILexer.h \ + ../../scintilla/include/Sci_Position.h \ + ../../scintilla/include/Scintilla.h \ + ../include/SciLexer.h \ + ../lexlib/WordList.h \ + ../lexlib/LexAccessor.h \ + ../lexlib/Accessor.h \ + ../lexlib/StyleContext.h \ + ../lexlib/CharacterSet.h \ + ../lexlib/LexerModule.h \ + ../lexlib/OptionSet.h \ + ../lexlib/DefaultLexer.h diff --git a/test/examples/zig/AllStyles.zig b/test/examples/zig/AllStyles.zig new file mode 100644 index 00000000..53a221fc --- /dev/null +++ b/test/examples/zig/AllStyles.zig @@ -0,0 +1,277 @@ +// coding:utf-8 + +/// A structure for storing a timestamp, with nanosecond precision (this is a +/// multiline doc comment). +const Timestamp = struct { + /// The number of seconds since the epoch (this is also a doc comment). + seconds: i64, // signed so we can represent pre-1970 (not a doc comment) + /// The number of nanoseconds past the second (doc comment again). + nanos: u32, + + /// Returns a `Timestamp` struct representing the Unix epoch; that is, the + /// moment of 1970 Jan 1 00:00:00 UTC (this is a doc comment too). + pub fn unixEpoch() Timestamp { + return Timestamp{ + .seconds = 0, + .nanos = 0, + }; + } +}; + +//! This module provides functions for retrieving the current date and +//! time with varying degrees of precision and accuracy. It does not +//! depend on libc, but will use functions from it if available. + +const S = struct { + //! Top level comments are allowed inside a container other than a module, + //! but it is not very useful. Currently, when producing the package + //! documentation, these comments are ignored. +}; + +const std = @import("std"); + +pub fn main() !void { + const stdout = std.io.getStdOut().writer(); + try stdout.print("Hello, {s}!\n", .{"world"}); +} + + +// Top-level declarations are order-independent: +const print = std.debug.print; +const std = @import("std"); +const os = std.os; +const assert = std.debug.assert; + +pub fn main() void { + // integers + const one_plus_one: i32 = 1 + 1; + print("1 + 1 = {}\n", .{one_plus_one}); + + // floats + const seven_div_three: f32 = 7.0 / 3.0; + print("7.0 / 3.0 = {}\n", .{seven_div_three}); + + // boolean + print("{}\n{}\n{}\n", .{ + true and false, + true or false, + !true, + }); + + // optional + var optional_value: ?[]const u8 = null; + assert(optional_value == null); + + print("\noptional 1\ntype: {}\nvalue: {?s}\n", .{ + @TypeOf(optional_value), optional_value, + }); + + optional_value = "hi"; + assert(optional_value != null); + + print("\noptional 2\ntype: {}\nvalue: {?s}\n", .{ + @TypeOf(optional_value), optional_value, + }); + + // error union + var number_or_error: anyerror!i32 = error.ArgNotFound; + + print("\nerror union 1\ntype: {}\nvalue: {!}\n", .{ + @TypeOf(number_or_error), + number_or_error, + }); + + number_or_error = 1234; + + print("\nerror union 2\ntype: {}\nvalue: {!}\n", .{ + @TypeOf(number_or_error), number_or_error, + }); +} + +const print = @import("std").debug.print; +const mem = @import("std").mem; // will be used to compare bytes + +pub fn main() void { + const bytes = "hello\u{12345678}"; + print("{}\n", .{@TypeOf(bytes)}); // *const [5:0]u8 + print("{d}\n", .{bytes.len}); // 5 + print("{c}\n", .{bytes[1]}); // 'e' + print("{d}\n", .{bytes[5]}); // 0 + print("{}\n", .{'e' == '\x65'}); // true + print("{d}\n", .{'\u{1f4a9}'}); // 128169 + print("{d}\n", .{'💯'}); // 128175 + print("{u}\n", .{'âš¡'}); + print("{}\n", .{mem.eql(u8, "hello", "h\x65llo")}); // true + print("{}\n", .{mem.eql(u8, "💯", "\xf0\x9f\x92\xaf")}); // also true + const invalid_utf8 = "\xff\xfe"; // non-UTF-8 strings are possible with \xNN notation. + print("0x{x}\n", .{invalid_utf8[1]}); // indexing them returns individual bytes... + print("0x{x}\n", .{"💯"[1]}); // ...as does indexing part-way through non-ASCII characters +} + +const hello_world_in_c = + \\#include + \\ + \\int main(int argc, char **argv) { + \\ printf("hello world\n"); + \\ return 0; + \\} +; + +const std = @import("std"); +const assert = std.debug.assert; + +threadlocal var x: i32 = 1234; + +test "thread local storage" { + const thread1 = try std.Thread.spawn(.{}, testTls, .{}); + const thread2 = try std.Thread.spawn(.{}, testTls, .{}); + testTls(); + thread1.join(); + thread2.join(); +} + +fn testTls() void { + assert(x == 1234); + x += 1; + assert(x == 1235); +} + +const decimal_int = 98222; +const hex_int = 0xff; +const another_hex_int = 0xFF; +const octal_int = 0o755; +const binary_int = 0b11110000; + +// underscores may be placed between two digits as a visual separator +const one_billion = 1_000_000_000; +const binary_mask = 0b1_1111_1111; +const permissions = 0o7_5_5; +const big_address = 0xFF80_0000_0000_0000; + + +const floating_point = 123.0E+77; +const another_float = 123.0; +const yet_another = 123.0e+77; + +const hex_floating_point = 0x103.70p-5; +const another_hex_float = 0x103.70; +const yet_another_hex_float = 0x103.70P-5; + +// underscores may be placed between two digits as a visual separator +const lightspeed = 299_792_458.000_000; +const nanosecond = 0.000_000_001; +const more_hex = 0x1234_5678.9ABC_CDEFp-10; + +const Vec3 = struct { + x: f32, + y: f32, + z: f32, + + pub fn init(x: f32, y: f32, z: f32) Vec3 { + return Vec3{ + .x = x, + .y = y, + .z = z, + }; + } + + pub fn dot(self: Vec3, other: Vec3) f32 { + return self.x * other.x + self.y * other.y + self.z * other.z; + } +}; + +fn LinkedList(comptime T: type) type { + return struct { + pub const Node = struct { + prev: ?*Node, + next: ?*Node, + data: T, + }; + + first: ?*Node, + last: ?*Node, + len: usize, + }; +} + +const Point = struct { + x: f32, + y: f32, +}; + +// Maybe we want to pass it to OpenGL so we want to be particular about +// how the bytes are arranged. +const Point2 = packed struct { + x: f32, + y: f32, +}; + + +const std = @import("std"); +const expect = std.testing.expect; + +const Color = enum { + auto, + off, + on, +}; + +const std = @import("std"); +const builtin = @import("builtin"); +const expect = std.testing.expect; + +test "switch simple" { + const a: u64 = 10; + const zz: u64 = 103; + + // All branches of a switch expression must be able to be coerced to a + // common type. + // + // Branches cannot fallthrough. If fallthrough behavior is desired, combine + // the cases and use an if. + const b = switch (a) { + // Multiple cases can be combined via a ',' + 1, 2, 3 => 0, + + // Ranges can be specified using the ... syntax. These are inclusive + // of both ends. + 5...100 => 1, + + // Branches can be arbitrarily complex. + 101 => blk: { + const c: u64 = 5; + break :blk c * 2 + 1; + }, + + // Switching on arbitrary expressions is allowed as long as the + // expression is known at compile-time. + zz => zz, + blk: { + const d: u32 = 5; + const e: u32 = 100; + break :blk d + e; + } => 107, + + // The else branch catches everything not already captured. + // Else branches are mandatory unless the entire range of values + // is handled. + else => 9, + }; + + try expect(b == 1); +} + +fn charToDigit(c: u8) u8 { + return switch (c) { + '0'...'9' => c - '0', + 'A'...'Z' => c - 'A' + 10, + 'a'...'z' => c - 'a' + 10, + else => maxInt(u8), + }; +} + +const optional_value: ?i32 = null; + +//! This module provides functions for retrieving the current date and +//! time with varying degrees of precision and accuracy. It does not +//! depend on libc, but will use functions from it if available. diff --git a/test/examples/zig/AllStyles.zig.folded b/test/examples/zig/AllStyles.zig.folded new file mode 100644 index 00000000..602db1f6 --- /dev/null +++ b/test/examples/zig/AllStyles.zig.folded @@ -0,0 +1,278 @@ + 0 400 400 // coding:utf-8 + 0 400 400 + 2 400 401 + /// A structure for storing a timestamp, with nanosecond precision (this is a + 0 401 400 | /// multiline doc comment). + 2 400 401 + const Timestamp = struct { + 0 401 401 | /// The number of seconds since the epoch (this is also a doc comment). + 0 401 401 | seconds: i64, // signed so we can represent pre-1970 (not a doc comment) + 0 401 401 | /// The number of nanoseconds past the second (doc comment again). + 0 401 401 | nanos: u32, + 0 401 401 | + 2 401 402 + /// Returns a `Timestamp` struct representing the Unix epoch; that is, the + 0 402 401 | /// moment of 1970 Jan 1 00:00:00 UTC (this is a doc comment too). + 2 401 402 + pub fn unixEpoch() Timestamp { + 2 402 403 + return Timestamp{ + 0 403 403 | .seconds = 0, + 0 403 403 | .nanos = 0, + 0 403 402 | }; + 0 402 401 | } + 0 401 400 | }; + 0 400 400 + 2 400 401 + //! This module provides functions for retrieving the current date and + 0 401 401 | //! time with varying degrees of precision and accuracy. It does not + 0 401 400 | //! depend on libc, but will use functions from it if available. + 0 400 400 + 2 400 401 + const S = struct { + 2 401 402 + //! Top level comments are allowed inside a container other than a module, + 0 402 402 | //! but it is not very useful. Currently, when producing the package + 0 402 401 | //! documentation, these comments are ignored. + 0 401 400 | }; + 0 400 400 + 0 400 400 const std = @import("std"); + 0 400 400 + 2 400 401 + pub fn main() !void { + 0 401 401 | const stdout = std.io.getStdOut().writer(); + 0 401 401 | try stdout.print("Hello, {s}!\n", .{"world"}); + 0 401 400 | } + 0 400 400 + 0 400 400 + 0 400 400 // Top-level declarations are order-independent: + 0 400 400 const print = std.debug.print; + 0 400 400 const std = @import("std"); + 0 400 400 const os = std.os; + 0 400 400 const assert = std.debug.assert; + 0 400 400 + 2 400 401 + pub fn main() void { + 0 401 401 | // integers + 0 401 401 | const one_plus_one: i32 = 1 + 1; + 0 401 401 | print("1 + 1 = {}\n", .{one_plus_one}); + 0 401 401 | + 0 401 401 | // floats + 0 401 401 | const seven_div_three: f32 = 7.0 / 3.0; + 0 401 401 | print("7.0 / 3.0 = {}\n", .{seven_div_three}); + 0 401 401 | + 0 401 401 | // boolean + 2 401 403 + print("{}\n{}\n{}\n", .{ + 0 403 403 | true and false, + 0 403 403 | true or false, + 0 403 403 | !true, + 0 403 401 | }); + 0 401 401 | + 0 401 401 | // optional + 0 401 401 | var optional_value: ?[]const u8 = null; + 0 401 401 | assert(optional_value == null); + 0 401 401 | + 2 401 403 + print("\noptional 1\ntype: {}\nvalue: {?s}\n", .{ + 0 403 403 | @TypeOf(optional_value), optional_value, + 0 403 401 | }); + 0 401 401 | + 0 401 401 | optional_value = "hi"; + 0 401 401 | assert(optional_value != null); + 0 401 401 | + 2 401 403 + print("\noptional 2\ntype: {}\nvalue: {?s}\n", .{ + 0 403 403 | @TypeOf(optional_value), optional_value, + 0 403 401 | }); + 0 401 401 | + 0 401 401 | // error union + 0 401 401 | var number_or_error: anyerror!i32 = error.ArgNotFound; + 0 401 401 | + 2 401 403 + print("\nerror union 1\ntype: {}\nvalue: {!}\n", .{ + 0 403 403 | @TypeOf(number_or_error), + 0 403 403 | number_or_error, + 0 403 401 | }); + 0 401 401 | + 0 401 401 | number_or_error = 1234; + 0 401 401 | + 2 401 403 + print("\nerror union 2\ntype: {}\nvalue: {!}\n", .{ + 0 403 403 | @TypeOf(number_or_error), number_or_error, + 0 403 401 | }); + 0 401 400 | } + 0 400 400 + 0 400 400 const print = @import("std").debug.print; + 0 400 400 const mem = @import("std").mem; // will be used to compare bytes + 0 400 400 + 2 400 401 + pub fn main() void { + 0 401 401 | const bytes = "hello\u{12345678}"; + 0 401 401 | print("{}\n", .{@TypeOf(bytes)}); // *const [5:0]u8 + 0 401 401 | print("{d}\n", .{bytes.len}); // 5 + 0 401 401 | print("{c}\n", .{bytes[1]}); // 'e' + 0 401 401 | print("{d}\n", .{bytes[5]}); // 0 + 0 401 401 | print("{}\n", .{'e' == '\x65'}); // true + 0 401 401 | print("{d}\n", .{'\u{1f4a9}'}); // 128169 + 0 401 401 | print("{d}\n", .{'💯'}); // 128175 + 0 401 401 | print("{u}\n", .{'âš¡'}); + 0 401 401 | print("{}\n", .{mem.eql(u8, "hello", "h\x65llo")}); // true + 0 401 401 | print("{}\n", .{mem.eql(u8, "💯", "\xf0\x9f\x92\xaf")}); // also true + 0 401 401 | const invalid_utf8 = "\xff\xfe"; // non-UTF-8 strings are possible with \xNN notation. + 0 401 401 | print("0x{x}\n", .{invalid_utf8[1]}); // indexing them returns individual bytes... + 0 401 401 | print("0x{x}\n", .{"💯"[1]}); // ...as does indexing part-way through non-ASCII characters + 0 401 400 | } + 0 400 400 + 0 400 400 const hello_world_in_c = + 2 400 401 + \\#include + 0 401 401 | \\ + 0 401 401 | \\int main(int argc, char **argv) { + 0 401 401 | \\ printf("hello world\n"); + 0 401 401 | \\ return 0; + 0 401 400 | \\} + 0 400 400 ; + 0 400 400 + 0 400 400 const std = @import("std"); + 0 400 400 const assert = std.debug.assert; + 0 400 400 + 0 400 400 threadlocal var x: i32 = 1234; + 0 400 400 + 2 400 401 + test "thread local storage" { + 0 401 401 | const thread1 = try std.Thread.spawn(.{}, testTls, .{}); + 0 401 401 | const thread2 = try std.Thread.spawn(.{}, testTls, .{}); + 0 401 401 | testTls(); + 0 401 401 | thread1.join(); + 0 401 401 | thread2.join(); + 0 401 400 | } + 0 400 400 + 2 400 401 + fn testTls() void { + 0 401 401 | assert(x == 1234); + 0 401 401 | x += 1; + 0 401 401 | assert(x == 1235); + 0 401 400 | } + 0 400 400 + 0 400 400 const decimal_int = 98222; + 0 400 400 const hex_int = 0xff; + 0 400 400 const another_hex_int = 0xFF; + 0 400 400 const octal_int = 0o755; + 0 400 400 const binary_int = 0b11110000; + 0 400 400 + 0 400 400 // underscores may be placed between two digits as a visual separator + 0 400 400 const one_billion = 1_000_000_000; + 0 400 400 const binary_mask = 0b1_1111_1111; + 0 400 400 const permissions = 0o7_5_5; + 0 400 400 const big_address = 0xFF80_0000_0000_0000; + 0 400 400 + 0 400 400 + 0 400 400 const floating_point = 123.0E+77; + 0 400 400 const another_float = 123.0; + 0 400 400 const yet_another = 123.0e+77; + 0 400 400 + 0 400 400 const hex_floating_point = 0x103.70p-5; + 0 400 400 const another_hex_float = 0x103.70; + 0 400 400 const yet_another_hex_float = 0x103.70P-5; + 0 400 400 + 0 400 400 // underscores may be placed between two digits as a visual separator + 0 400 400 const lightspeed = 299_792_458.000_000; + 0 400 400 const nanosecond = 0.000_000_001; + 0 400 400 const more_hex = 0x1234_5678.9ABC_CDEFp-10; + 0 400 400 + 2 400 401 + const Vec3 = struct { + 0 401 401 | x: f32, + 0 401 401 | y: f32, + 0 401 401 | z: f32, + 0 401 401 | + 2 401 402 + pub fn init(x: f32, y: f32, z: f32) Vec3 { + 2 402 403 + return Vec3{ + 0 403 403 | .x = x, + 0 403 403 | .y = y, + 0 403 403 | .z = z, + 0 403 402 | }; + 0 402 401 | } + 0 401 401 | + 2 401 402 + pub fn dot(self: Vec3, other: Vec3) f32 { + 0 402 402 | return self.x * other.x + self.y * other.y + self.z * other.z; + 0 402 401 | } + 0 401 400 | }; + 0 400 400 + 2 400 401 + fn LinkedList(comptime T: type) type { + 2 401 402 + return struct { + 2 402 403 + pub const Node = struct { + 0 403 403 | prev: ?*Node, + 0 403 403 | next: ?*Node, + 0 403 403 | data: T, + 0 403 402 | }; + 0 402 402 | + 0 402 402 | first: ?*Node, + 0 402 402 | last: ?*Node, + 0 402 402 | len: usize, + 0 402 401 | }; + 0 401 400 | } + 0 400 400 + 2 400 401 + const Point = struct { + 0 401 401 | x: f32, + 0 401 401 | y: f32, + 0 401 400 | }; + 0 400 400 + 2 400 401 + // Maybe we want to pass it to OpenGL so we want to be particular about + 0 401 400 | // how the bytes are arranged. + 2 400 401 + const Point2 = packed struct { + 0 401 401 | x: f32, + 0 401 401 | y: f32, + 0 401 400 | }; + 0 400 400 + 0 400 400 + 0 400 400 const std = @import("std"); + 0 400 400 const expect = std.testing.expect; + 0 400 400 + 2 400 401 + const Color = enum { + 0 401 401 | auto, + 0 401 401 | off, + 0 401 401 | on, + 0 401 400 | }; + 0 400 400 + 0 400 400 const std = @import("std"); + 0 400 400 const builtin = @import("builtin"); + 0 400 400 const expect = std.testing.expect; + 0 400 400 + 2 400 401 + test "switch simple" { + 0 401 401 | const a: u64 = 10; + 0 401 401 | const zz: u64 = 103; + 0 401 401 | + 2 401 402 + // All branches of a switch expression must be able to be coerced to a + 0 402 402 | // common type. + 0 402 402 | // + 0 402 402 | // Branches cannot fallthrough. If fallthrough behavior is desired, combine + 0 402 401 | // the cases and use an if. + 2 401 402 + const b = switch (a) { + 0 402 402 | // Multiple cases can be combined via a ',' + 0 402 402 | 1, 2, 3 => 0, + 0 402 402 | + 2 402 403 + // Ranges can be specified using the ... syntax. These are inclusive + 0 403 402 | // of both ends. + 0 402 402 | 5...100 => 1, + 0 402 402 | + 0 402 402 | // Branches can be arbitrarily complex. + 2 402 403 + 101 => blk: { + 0 403 403 | const c: u64 = 5; + 0 403 403 | break :blk c * 2 + 1; + 0 403 402 | }, + 0 402 402 | + 2 402 403 + // Switching on arbitrary expressions is allowed as long as the + 0 403 402 | // expression is known at compile-time. + 0 402 402 | zz => zz, + 2 402 403 + blk: { + 0 403 403 | const d: u32 = 5; + 0 403 403 | const e: u32 = 100; + 0 403 403 | break :blk d + e; + 0 403 402 | } => 107, + 0 402 402 | + 2 402 403 + // The else branch catches everything not already captured. + 0 403 403 | // Else branches are mandatory unless the entire range of values + 0 403 402 | // is handled. + 0 402 402 | else => 9, + 0 402 401 | }; + 0 401 401 | + 0 401 401 | try expect(b == 1); + 0 401 400 | } + 0 400 400 + 2 400 401 + fn charToDigit(c: u8) u8 { + 2 401 402 + return switch (c) { + 0 402 402 | '0'...'9' => c - '0', + 0 402 402 | 'A'...'Z' => c - 'A' + 10, + 0 402 402 | 'a'...'z' => c - 'a' + 10, + 0 402 402 | else => maxInt(u8), + 0 402 401 | }; + 0 401 400 | } + 0 400 400 + 0 400 400 const optional_value: ?i32 = null; + 0 400 400 + 2 400 401 + //! This module provides functions for retrieving the current date and + 0 401 401 | //! time with varying degrees of precision and accuracy. It does not + 0 401 400 | //! depend on libc, but will use functions from it if available. + 0 400 0 \ No newline at end of file diff --git a/test/examples/zig/AllStyles.zig.styled b/test/examples/zig/AllStyles.zig.styled new file mode 100644 index 00000000..67afab7c --- /dev/null +++ b/test/examples/zig/AllStyles.zig.styled @@ -0,0 +1,277 @@ +{1}// coding:utf-8 +{0} +{2}/// A structure for storing a timestamp, with nanosecond precision (this is a +/// multiline doc comment). +{13}const{0} {15}Timestamp{0} {5}={0} {13}struct{0} {5}{{0} + {2}/// The number of seconds since the epoch (this is also a doc comment). +{0} {10}seconds{5}:{0} {14}i64{5},{0} {1}// signed so we can represent pre-1970 (not a doc comment) +{0} {2}/// The number of nanoseconds past the second (doc comment again). +{0} {10}nanos{5}:{0} {14}u32{5},{0} + + {2}/// Returns a `Timestamp` struct representing the Unix epoch; that is, the +{0} {2}/// moment of 1970 Jan 1 00:00:00 UTC (this is a doc comment too). +{0} {13}pub{0} {13}fn{0} {11}unixEpoch{5}(){0} {15}Timestamp{0} {5}{{0} + {13}return{0} {15}Timestamp{5}{{0} + {5}.{10}seconds{0} {5}={0} {4}0{5},{0} + {5}.{10}nanos{0} {5}={0} {4}0{5},{0} + {5}};{0} + {5}}{0} +{5}};{0} + +{3}//! This module provides functions for retrieving the current date and +//! time with varying degrees of precision and accuracy. It does not +//! depend on libc, but will use functions from it if available. +{0} +{13}const{0} {10}S{0} {5}={0} {13}struct{0} {5}{{0} + {3}//! Top level comments are allowed inside a container other than a module, +{0} {3}//! but it is not very useful. Currently, when producing the package +{0} {3}//! documentation, these comments are ignored. +{5}};{0} + +{13}const{0} {10}std{0} {5}={0} {12}@import{5}({7}"std"{5});{0} + +{13}pub{0} {13}fn{0} {11}main{5}(){0} {5}!{14}void{0} {5}{{0} + {13}const{0} {10}stdout{0} {5}={0} {10}std{5}.{10}io{5}.{10}getStdOut{5}().{10}writer{5}();{0} + {13}try{0} {10}stdout{5}.{10}print{5}({7}"Hello, {s}!{9}\n{7}"{5},{0} {5}.{{7}"world"{5}});{0} +{5}}{0} + + +{1}// Top-level declarations are order-independent: +{13}const{0} {10}print{0} {5}={0} {10}std{5}.{10}debug{5}.{10}print{5};{0} +{13}const{0} {10}std{0} {5}={0} {12}@import{5}({7}"std"{5});{0} +{13}const{0} {10}os{0} {5}={0} {10}std{5}.{10}os{5};{0} +{13}const{0} {13}assert{0} {5}={0} {10}std{5}.{10}debug{5}.{13}assert{5};{0} + +{13}pub{0} {13}fn{0} {11}main{5}(){0} {14}void{0} {5}{{0} + {1}// integers +{0} {13}const{0} {10}one_plus_one{5}:{0} {14}i32{0} {5}={0} {4}1{0} {5}+{0} {4}1{5};{0} + {10}print{5}({7}"1 + 1 = {}{9}\n{7}"{5},{0} {5}.{{10}one_plus_one{5}});{0} + + {1}// floats +{0} {13}const{0} {10}seven_div_three{5}:{0} {14}f32{0} {5}={0} {4}7.0{0} {5}/{0} {4}3.0{5};{0} + {10}print{5}({7}"7.0 / 3.0 = {}{9}\n{7}"{5},{0} {5}.{{10}seven_div_three{5}});{0} + + {1}// boolean +{0} {10}print{5}({7}"{}{9}\n{7}{}{9}\n{7}{}{9}\n{7}"{5},{0} {5}.{{0} + {13}true{0} {13}and{0} {13}false{5},{0} + {13}true{0} {13}or{0} {13}false{5},{0} + {5}!{13}true{5},{0} + {5}});{0} + + {1}// optional +{0} {13}var{0} {10}optional_value{5}:{0} {5}?[]{13}const{0} {14}u8{0} {5}={0} {13}null{5};{0} + {13}assert{5}({10}optional_value{0} {5}=={0} {13}null{5});{0} + + {10}print{5}({7}"{9}\n{7}optional 1{9}\n{7}type: {}{9}\n{7}value: {?s}{9}\n{7}"{5},{0} {5}.{{0} + {12}@TypeOf{5}({10}optional_value{5}),{0} {10}optional_value{5},{0} + {5}});{0} + + {10}optional_value{0} {5}={0} {7}"hi"{5};{0} + {13}assert{5}({10}optional_value{0} {5}!={0} {13}null{5});{0} + + {10}print{5}({7}"{9}\n{7}optional 2{9}\n{7}type: {}{9}\n{7}value: {?s}{9}\n{7}"{5},{0} {5}.{{0} + {12}@TypeOf{5}({10}optional_value{5}),{0} {10}optional_value{5},{0} + {5}});{0} + + {1}// error union +{0} {13}var{0} {10}number_or_error{5}:{0} {14}anyerror{5}!{14}i32{0} {5}={0} {13}error{5}.{10}ArgNotFound{5};{0} + + {10}print{5}({7}"{9}\n{7}error union 1{9}\n{7}type: {}{9}\n{7}value: {!}{9}\n{7}"{5},{0} {5}.{{0} + {12}@TypeOf{5}({10}number_or_error{5}),{0} + {10}number_or_error{5},{0} + {5}});{0} + + {10}number_or_error{0} {5}={0} {4}1234{5};{0} + + {10}print{5}({7}"{9}\n{7}error union 2{9}\n{7}type: {}{9}\n{7}value: {!}{9}\n{7}"{5},{0} {5}.{{0} + {12}@TypeOf{5}({10}number_or_error{5}),{0} {10}number_or_error{5},{0} + {5}});{0} +{5}}{0} + +{13}const{0} {10}print{0} {5}={0} {12}@import{5}({7}"std"{5}).{10}debug{5}.{10}print{5};{0} +{13}const{0} {10}mem{0} {5}={0} {12}@import{5}({7}"std"{5}).{10}mem{5};{0} {1}// will be used to compare bytes +{0} +{13}pub{0} {13}fn{0} {11}main{5}(){0} {14}void{0} {5}{{0} + {13}const{0} {10}bytes{0} {5}={0} {7}"hello{9}\u{12345678}{7}"{5};{0} + {10}print{5}({7}"{}{9}\n{7}"{5},{0} {5}.{{12}@TypeOf{5}({10}bytes{5})});{0} {1}// *const [5:0]u8 +{0} {10}print{5}({7}"{d}{9}\n{7}"{5},{0} {5}.{{10}bytes{5}.{10}len{5}});{0} {1}// 5 +{0} {10}print{5}({7}"{c}{9}\n{7}"{5},{0} {5}.{{10}bytes{5}[{4}1{5}]});{0} {1}// 'e' +{0} {10}print{5}({7}"{d}{9}\n{7}"{5},{0} {5}.{{10}bytes{5}[{4}5{5}]});{0} {1}// 0 +{0} {10}print{5}({7}"{}{9}\n{7}"{5},{0} {5}.{{6}'e'{0} {5}=={0} {6}'{9}\x65{6}'{5}});{0} {1}// true +{0} {10}print{5}({7}"{d}{9}\n{7}"{5},{0} {5}.{{6}'{9}\u{1f4a9}{6}'{5}});{0} {1}// 128169 +{0} {10}print{5}({7}"{d}{9}\n{7}"{5},{0} {5}.{{6}'💯'{5}});{0} {1}// 128175 +{0} {10}print{5}({7}"{u}{9}\n{7}"{5},{0} {5}.{{6}'âš¡'{5}});{0} + {10}print{5}({7}"{}{9}\n{7}"{5},{0} {5}.{{10}mem{5}.{10}eql{5}({14}u8{5},{0} {7}"hello"{5},{0} {7}"h{9}\x65{7}llo"{5})});{0} {1}// true +{0} {10}print{5}({7}"{}{9}\n{7}"{5},{0} {5}.{{10}mem{5}.{10}eql{5}({14}u8{5},{0} {7}"💯"{5},{0} {7}"{9}\xf0\x9f\x92\xaf{7}"{5})});{0} {1}// also true +{0} {13}const{0} {10}invalid_utf8{0} {5}={0} {7}"{9}\xff\xfe{7}"{5};{0} {1}// non-UTF-8 strings are possible with \xNN notation. +{0} {10}print{5}({7}"0x{x}{9}\n{7}"{5},{0} {5}.{{10}invalid_utf8{5}[{4}1{5}]});{0} {1}// indexing them returns individual bytes... +{0} {10}print{5}({7}"0x{x}{9}\n{7}"{5},{0} {5}.{{7}"💯"{5}[{4}1{5}]});{0} {1}// ...as does indexing part-way through non-ASCII characters +{5}}{0} + +{13}const{0} {10}hello_world_in_c{0} {5}={0} + {8}\\#include +{0} {8}\\ +{0} {8}\\int main(int argc, char **argv) { +{0} {8}\\ printf("hello world\n"); +{0} {8}\\ return 0; +{0} {8}\\} +{5};{0} + +{13}const{0} {10}std{0} {5}={0} {12}@import{5}({7}"std"{5});{0} +{13}const{0} {13}assert{0} {5}={0} {10}std{5}.{10}debug{5}.{13}assert{5};{0} + +{13}threadlocal{0} {13}var{0} {10}x{5}:{0} {14}i32{0} {5}={0} {4}1234{5};{0} + +{13}test{0} {7}"thread local storage"{0} {5}{{0} + {13}const{0} {10}thread1{0} {5}={0} {13}try{0} {10}std{5}.{10}Thread{5}.{10}spawn{5}(.{},{0} {10}testTls{5},{0} {5}.{});{0} + {13}const{0} {10}thread2{0} {5}={0} {13}try{0} {10}std{5}.{10}Thread{5}.{10}spawn{5}(.{},{0} {10}testTls{5},{0} {5}.{});{0} + {10}testTls{5}();{0} + {10}thread1{5}.{10}join{5}();{0} + {10}thread2{5}.{10}join{5}();{0} +{5}}{0} + +{13}fn{0} {11}testTls{5}(){0} {14}void{0} {5}{{0} + {13}assert{5}({10}x{0} {5}=={0} {4}1234{5});{0} + {10}x{0} {5}+={0} {4}1{5};{0} + {13}assert{5}({10}x{0} {5}=={0} {4}1235{5});{0} +{5}}{0} + +{13}const{0} {10}decimal_int{0} {5}={0} {4}98222{5};{0} +{13}const{0} {10}hex_int{0} {5}={0} {4}0xff{5};{0} +{13}const{0} {10}another_hex_int{0} {5}={0} {4}0xFF{5};{0} +{13}const{0} {10}octal_int{0} {5}={0} {4}0o755{5};{0} +{13}const{0} {10}binary_int{0} {5}={0} {4}0b11110000{5};{0} + +{1}// underscores may be placed between two digits as a visual separator +{13}const{0} {10}one_billion{0} {5}={0} {4}1_000_000_000{5};{0} +{13}const{0} {10}binary_mask{0} {5}={0} {4}0b1_1111_1111{5};{0} +{13}const{0} {10}permissions{0} {5}={0} {4}0o7_5_5{5};{0} +{13}const{0} {10}big_address{0} {5}={0} {4}0xFF80_0000_0000_0000{5};{0} + + +{13}const{0} {10}floating_point{0} {5}={0} {4}123.0E+77{5};{0} +{13}const{0} {10}another_float{0} {5}={0} {4}123.0{5};{0} +{13}const{0} {10}yet_another{0} {5}={0} {4}123.0e+77{5};{0} + +{13}const{0} {10}hex_floating_point{0} {5}={0} {4}0x103.70p{5}-{4}5{5};{0} +{13}const{0} {10}another_hex_float{0} {5}={0} {4}0x103.70{5};{0} +{13}const{0} {10}yet_another_hex_float{0} {5}={0} {4}0x103.70P{5}-{4}5{5};{0} + +{1}// underscores may be placed between two digits as a visual separator +{13}const{0} {10}lightspeed{0} {5}={0} {4}299_792_458.000_000{5};{0} +{13}const{0} {10}nanosecond{0} {5}={0} {4}0.000_000_001{5};{0} +{13}const{0} {10}more_hex{0} {5}={0} {4}0x1234_5678.9ABC_CDEFp{5}-{4}10{5};{0} + +{13}const{0} {16}Vec3{0} {5}={0} {13}struct{0} {5}{{0} + {10}x{5}:{0} {14}f32{5},{0} + {10}y{5}:{0} {14}f32{5},{0} + {10}z{5}:{0} {14}f32{5},{0} + + {13}pub{0} {13}fn{0} {11}init{5}({10}x{5}:{0} {14}f32{5},{0} {10}y{5}:{0} {14}f32{5},{0} {10}z{5}:{0} {14}f32{5}){0} {16}Vec3{0} {5}{{0} + {13}return{0} {16}Vec3{5}{{0} + {5}.{10}x{0} {5}={0} {10}x{5},{0} + {5}.{10}y{0} {5}={0} {10}y{5},{0} + {5}.{10}z{0} {5}={0} {10}z{5},{0} + {5}};{0} + {5}}{0} + + {13}pub{0} {13}fn{0} {11}dot{5}({10}self{5}:{0} {16}Vec3{5},{0} {10}other{5}:{0} {16}Vec3{5}){0} {14}f32{0} {5}{{0} + {13}return{0} {10}self{5}.{10}x{0} {5}*{0} {10}other{5}.{10}x{0} {5}+{0} {10}self{5}.{10}y{0} {5}*{0} {10}other{5}.{10}y{0} {5}+{0} {10}self{5}.{10}z{0} {5}*{0} {10}other{5}.{10}z{5};{0} + {5}}{0} +{5}};{0} + +{13}fn{0} {11}LinkedList{5}({13}comptime{0} {10}T{5}:{0} {14}type{5}){0} {14}type{0} {5}{{0} + {13}return{0} {13}struct{0} {5}{{0} + {13}pub{0} {13}const{0} {10}Node{0} {5}={0} {13}struct{0} {5}{{0} + {10}prev{5}:{0} {5}?*{10}Node{5},{0} + {10}next{5}:{0} {5}?*{10}Node{5},{0} + {10}data{5}:{0} {10}T{5},{0} + {5}};{0} + + {10}first{5}:{0} {5}?*{10}Node{5},{0} + {10}last{5}:{0} {5}?*{10}Node{5},{0} + {10}len{5}:{0} {14}usize{5},{0} + {5}};{0} +{5}}{0} + +{13}const{0} {10}Point{0} {5}={0} {13}struct{0} {5}{{0} + {10}x{5}:{0} {14}f32{5},{0} + {10}y{5}:{0} {14}f32{5},{0} +{5}};{0} + +{1}// Maybe we want to pass it to OpenGL so we want to be particular about +// how the bytes are arranged. +{13}const{0} {10}Point2{0} {5}={0} {13}packed{0} {13}struct{0} {5}{{0} + {10}x{5}:{0} {14}f32{5},{0} + {10}y{5}:{0} {14}f32{5},{0} +{5}};{0} + + +{13}const{0} {10}std{0} {5}={0} {12}@import{5}({7}"std"{5});{0} +{13}const{0} {10}expect{0} {5}={0} {10}std{5}.{10}testing{5}.{10}expect{5};{0} + +{13}const{0} {10}Color{0} {5}={0} {13}enum{0} {5}{{0} + {10}auto{5},{0} + {10}off{5},{0} + {10}on{5},{0} +{5}};{0} + +{13}const{0} {10}std{0} {5}={0} {12}@import{5}({7}"std"{5});{0} +{13}const{0} {10}builtin{0} {5}={0} {12}@import{5}({7}"builtin"{5});{0} +{13}const{0} {10}expect{0} {5}={0} {10}std{5}.{10}testing{5}.{10}expect{5};{0} + +{13}test{0} {7}"switch simple"{0} {5}{{0} + {13}const{0} {10}a{5}:{0} {14}u64{0} {5}={0} {4}10{5};{0} + {13}const{0} {10}zz{5}:{0} {14}u64{0} {5}={0} {4}103{5};{0} + + {1}// All branches of a switch expression must be able to be coerced to a +{0} {1}// common type. +{0} {1}// +{0} {1}// Branches cannot fallthrough. If fallthrough behavior is desired, combine +{0} {1}// the cases and use an if. +{0} {13}const{0} {10}b{0} {5}={0} {13}switch{0} {5}({10}a{5}){0} {5}{{0} + {1}// Multiple cases can be combined via a ',' +{0} {4}1{5},{0} {4}2{5},{0} {4}3{0} {5}=>{0} {4}0{5},{0} + + {1}// Ranges can be specified using the ... syntax. These are inclusive +{0} {1}// of both ends. +{0} {4}5{5}..{4}.100{0} {5}=>{0} {4}1{5},{0} + + {1}// Branches can be arbitrarily complex. +{0} {4}101{0} {5}=>{0} {10}blk{5}:{0} {5}{{0} + {13}const{0} {10}c{5}:{0} {14}u64{0} {5}={0} {4}5{5};{0} + {13}break{0} {5}:{10}blk{0} {10}c{0} {5}*{0} {4}2{0} {5}+{0} {4}1{5};{0} + {5}},{0} + + {1}// Switching on arbitrary expressions is allowed as long as the +{0} {1}// expression is known at compile-time. +{0} {10}zz{0} {5}=>{0} {10}zz{5},{0} + {10}blk{5}:{0} {5}{{0} + {13}const{0} {10}d{5}:{0} {14}u32{0} {5}={0} {4}5{5};{0} + {13}const{0} {10}e{5}:{0} {14}u32{0} {5}={0} {4}100{5};{0} + {13}break{0} {5}:{10}blk{0} {10}d{0} {5}+{0} {10}e{5};{0} + {5}}{0} {5}=>{0} {4}107{5},{0} + + {1}// The else branch catches everything not already captured. +{0} {1}// Else branches are mandatory unless the entire range of values +{0} {1}// is handled. +{0} {13}else{0} {5}=>{0} {4}9{5},{0} + {5}};{0} + + {13}try{0} {10}expect{5}({10}b{0} {5}=={0} {4}1{5});{0} +{5}}{0} + +{13}fn{0} {11}charToDigit{5}({10}c{5}:{0} {14}u8{5}){0} {14}u8{0} {5}{{0} + {13}return{0} {13}switch{0} {5}({10}c{5}){0} {5}{{0} + {6}'0'{5}...{6}'9'{0} {5}=>{0} {10}c{0} {5}-{0} {6}'0'{5},{0} + {6}'A'{5}...{6}'Z'{0} {5}=>{0} {10}c{0} {5}-{0} {6}'A'{0} {5}+{0} {4}10{5},{0} + {6}'a'{5}...{6}'z'{0} {5}=>{0} {10}c{0} {5}-{0} {6}'a'{0} {5}+{0} {4}10{5},{0} + {13}else{0} {5}=>{0} {10}maxInt{5}({14}u8{5}),{0} + {5}};{0} +{5}}{0} + +{13}const{0} {10}optional_value{5}:{0} {5}?{14}i32{0} {5}={0} {13}null{5};{0} + +{3}//! This module provides functions for retrieving the current date and +//! time with varying degrees of precision and accuracy. It does not +//! depend on libc, but will use functions from it if available. diff --git a/test/examples/zig/SciTE.properties b/test/examples/zig/SciTE.properties new file mode 100644 index 00000000..16718720 --- /dev/null +++ b/test/examples/zig/SciTE.properties @@ -0,0 +1,6 @@ +lexer.*.zig=zig +fold=1 +keywords.*.zig=False None True _ and as assert async await break case class continue def del elif else except finally for from global if import in is lambda match nonlocal not or pass raise return try while with yield addrspace align allowzero and anyframe anytype asm async await break callconv catch comptime const continue defer else enum errdefer error export extern false fn for if inline linksection noalias noinline nosuspend null opaque or orelse packed pub resume return struct suspend switch test threadlocal true try undefined union unreachable usingnamespace var volatile while +keywords2.*.zig=anyerror anyopaque bool f128 f16 f32 f64 f80 i128 i16 i32 i64 i8 isize noreturn type u128 u16 u32 u64 u8 usize void +keywords3.*.zig=Timestamp +keywords4.*.zig=Vec3