unit u_sxsyn; {$I u_defines.inc} interface uses Classes, SynEditHighlighter, SynEditHighlighterFoldBase, SynEditTypes, u_common; type KeywordMatch = record private { rendered on 2021-Oct-31 06:16:53.798781 by IsItThere. - PRNG seed: 6574 - map length: 128 - case sensitive: true } const fWords: array [0..127] of string = ('', '', 'alias', 'this', 'f32', '', 's32', 's8', 'throw', 'f64', 'switch', 's64', '', '', '', '', '', '', 'finally', '', '', '', 'if', '', '', '', '', '', '', '', '', '', '', '', '', '', 'protection', 's16', '', '', 'goto', 'usize', '', '', 'in', '', 'static', '', 'try', '', '', '', 'enum', 'do', '', '', '', 'super', 'const', 'union', '', '', 'else', '', 'version', '', '', '', '', 'u32', 'u8', 'echo', '', 'true', 'u64', 'asm', '', 'struct', '', 'auto', 'bool', '', '', '', '', '', 'false', 'null', 'class', '', '', 'overload', '', '', '', '', 'label', '', 'assert', 'continue', 'u16', 'foreach', 'break', '', '', '', 'ssize', '', '', '', '', 'unit', 'while', '', 'var', '', 'with', 'template', '', 'import', 'on', '', '', 'function', '', 'return', '', ''); const fFilled: array [0..127] of boolean = (false, false, true, true, true, false, true, true, true, true, true, true, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, true, true, false, false, true, false, true, false, true, false, false, false, true, true, false, false, false, true, true, true, false, false, true, false, true, false, false, false, false, true, true, true, false, true, true, true, false, true, false, true, true, false, false, false, false, false, true, true, true, false, false, true, false, false, false, false, true, false, true, true, true, true, true, false, false, false, true, false, false, false, false, true, true, false, true, false, true, true, false, true, true, false, false, true, false, true, false, false); const fCoefficients: array [0..255] of Byte = (251, 141, 241, 229, 153, 224, 69, 154, 183, 60, 181, 128, 168, 190, 25, 39, 142, 116, 172, 48, 49, 203, 195, 46, 229, 38, 232, 88, 114, 147, 97, 185, 242, 43, 34, 75, 89, 228, 21, 156, 254, 129, 186, 74, 224, 78, 146, 25, 49, 118, 232, 70, 92, 34, 215, 44, 47, 48, 153, 28, 19, 111, 146, 97, 159, 224, 143, 72, 212, 194, 30, 104, 134, 217, 123, 30, 68, 206, 208, 50, 96, 3, 30, 30, 90, 245, 234, 93, 191, 97, 112, 45, 103, 11, 225, 255, 132, 128, 78, 62, 41, 62, 214, 100, 191, 64, 95, 146, 234, 243, 236, 12, 68, 60, 72, 216, 44, 23, 42, 201, 206, 188, 188, 190, 114, 193, 20, 143, 119, 31, 235, 96, 72, 92, 146, 146, 227, 33, 253, 76, 142, 189, 58, 38, 203, 68, 19, 35, 82, 49, 150, 78, 157, 199, 33, 210, 223, 133, 237, 56, 89, 123, 20, 177, 68, 205, 21, 128, 142, 35, 222, 180, 138, 141, 10, 160, 212, 166, 255, 166, 75, 212, 216, 239, 76, 119, 45, 62, 130, 21, 116, 119, 253, 50, 241, 160, 208, 225, 244, 55, 57, 238, 239, 107, 190, 143, 165, 125, 217, 80, 18, 244, 72, 210, 28, 77, 138, 40, 239, 124, 75, 87, 92, 121, 107, 222, 0, 23, 215, 213, 133, 144, 208, 216, 191, 170, 75, 182, 75, 230, 218, 136, 44, 134, 191, 183, 126, 108, 58, 29, 52, 163, 111, 131, 198, 230); class function hash(const w: string): Word; static; public class function contains(const w: string): boolean; static; end; TTokenKind = (tkNone, tkError, tkCommt, tkIdent, tkKeywd, tkStrng, tkBlank, tkSymbl, tkNumbr, tkAttri); TRangeKind = (rkNone, rkString1, rkString2, rkBlockCom1, rkAttrib); TSynSxSynRange = class (TSynCustomHighlighterRange) private rangeKind : TRangeKind; public procedure Assign(source: TSynCustomHighlighterRange); override; function Compare(range: TSynCustomHighlighterRange): integer; override; procedure Clear; override; procedure copyFrom(source: TSynSxSynRange); end; TSynSxSyn = class (TSynCustomFoldHighlighter) private fWhiteAttrib: TSynHighlighterAttributes; fNumbrAttrib: TSynHighlighterAttributes; fSymblAttrib: TSynHighlighterAttributes; fIdentAttrib: TSynHighlighterAttributes; fCommtAttrib: TSynHighlighterAttributes; fStrngAttrib: TSynHighlighterAttributes; fKeywdAttrib: TSynHighlighterAttributes; fAttriAttrib: TSynHighlighterAttributes; fErrorAttrib: TSynHighlighterAttributes; fLineBuf: string; fTokStart, fTokStop: Integer; fTokKind: TTokenKind; fCurrRange: TSynSxSynRange; fLineNum: integer; fAttribLut: array[TTokenKind] of TSynHighlighterAttributes; procedure setWhiteAttrib(value: TSynHighlighterAttributes); procedure setNumbrAttrib(value: TSynHighlighterAttributes); procedure setSymblAttrib(value: TSynHighlighterAttributes); procedure setIdentAttrib(value: TSynHighlighterAttributes); procedure setCommtAttrib(value: TSynHighlighterAttributes); procedure setStrngAttrib(value: TSynHighlighterAttributes); procedure setKeywdAttrib(value: TSynHighlighterAttributes); procedure setAttriAttrib(value: TSynHighlighterAttributes); procedure setErrorAttrib(value: TSynHighlighterAttributes); function safeLookupChar(): PChar; function canLookup2Char(): boolean; procedure lexOpAndOpEqual(); procedure lexOpAndOpOpAndOpEqual(const op: char); procedure lexOpAndOpOpAndOpEqualAndOpOpEqual(const op: char); procedure lexAssEquOrLambda(); procedure lexHexLiteral(); procedure lexBinLiteral(); procedure lexIntLiteral(); procedure lexFloatingLiteralFractionalPart(); procedure lexExponent(); procedure lexStringLiteral(); procedure lexRawStringLiteral(); procedure lexLineComment(); procedure lexStarComment(); procedure lexIdentifier(); protected function GetRangeClass: TSynCustomHighlighterRangeClass; override; function GetIdentChars: TSynIdentChars; override; public constructor create(aOwner: TComponent); override; destructor destroy; override; procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override; function GetDefaultAttribute(Index: integer): TSynHighlighterAttributes; override; procedure setLine(const NewValue: string; LineNumber: Integer); override; procedure next; override; function GetTokenAttribute: TSynHighlighterAttributes; override; function GetToken: string; override; function GetTokenKind: integer; override; function GetTokenPos: Integer; override; function GetEol: Boolean; override; procedure SetRange(value: Pointer); override; procedure ResetRange; override; function GetRange: Pointer; override; property whites: TSynHighlighterAttributes read fWhiteAttrib write setWhiteAttrib stored true; property numbers: TSynHighlighterAttributes read fNumbrAttrib write setNumbrAttrib stored true; property symbols: TSynHighlighterAttributes read fSymblAttrib write setSymblAttrib stored true; property identifiers: TSynHighlighterAttributes read fIdentAttrib write setIdentAttrib stored true; property comments: TSynHighlighterAttributes read fCommtAttrib write setCommtAttrib stored true; property strings: TSynHighlighterAttributes read fStrngAttrib write setStrngAttrib stored true; property keywords: TSynHighlighterAttributes read fKeywdAttrib write setKeywdAttrib stored true; property attributes: TSynHighlighterAttributes read fAttriAttrib write setAttriAttrib stored true; property errors: TSynHighlighterAttributes read fErrorAttrib write setErrorAttrib stored true; end; implementation {$PUSH}{$R-} class function KeywordMatch.hash(const w: string): Word; var i: integer; begin Result := 0; for i := 1 to length(w) do Result += fCoefficients[Byte(w[i])]; Result := Result mod 128; end; class function KeywordMatch.contains(const w: string): boolean; var h: Word; begin result := false; h := hash(w); if fFilled[h] then result := fWords[h] = w; end; {$POP} procedure TSynSxSynRange.Assign(source: TSynCustomHighlighterRange); var rng: TSynSxSynRange; begin inherited; if source is TSynSxSynRange then begin rng := TSynSxSynRange(source); rangeKind := rng.rangeKind; end; end; function TSynSxSynRange.Compare(range: TSynCustomHighlighterRange): integer; begin result := inherited Compare(range); assert(range <> nil); if not result.equals(0) then exit; if range is TSynSxSynRange then result := integer(rangeKind = TSynSxSynRange(range).rangeKind); end; procedure TSynSxSynRange.Clear; begin rangeKind := TRangeKind.rkNone; end; procedure TSynSxSynRange.copyFrom(source: TSynSxSynRange); begin if source.isAssigned then rangeKind := source.rangeKind; end; constructor TSynSxSyn.create(aOwner: TComponent); begin inherited create(aOwner); DefaultFilter:= 'STYX source|*.sx|STYX archive|*.sar'; WordBreakChars := WordBreakChars - ['@']; fWhiteAttrib := TSynHighlighterAttributes.Create('White','White'); fNumbrAttrib := TSynHighlighterAttributes.Create('Numbr','Numbr'); fSymblAttrib := TSynHighlighterAttributes.Create('Symbl','Symbl'); fIdentAttrib := TSynHighlighterAttributes.Create('Ident','Ident'); fCommtAttrib := TSynHighlighterAttributes.Create('Commt','Commt'); fStrngAttrib := TSynHighlighterAttributes.Create('Strng','Strng'); fKeywdAttrib := TSynHighlighterAttributes.Create('Keywd','Keywd'); fAttriAttrib := TSynHighlighterAttributes.Create('Attri','Attri'); fErrorAttrib := TSynHighlighterAttributes.Create('Error','Error'); AddAttribute(fWhiteAttrib); AddAttribute(fNumbrAttrib); AddAttribute(fSymblAttrib); AddAttribute(fIdentAttrib); AddAttribute(fCommtAttrib); AddAttribute(fStrngAttrib); AddAttribute(fKeywdAttrib); AddAttribute(fAttriAttrib); AddAttribute(fErrorAttrib); fAttribLut[TTokenKind.tkident] := fIdentAttrib; fAttribLut[TTokenKind.tkBlank] := fWhiteAttrib; fAttribLut[TTokenKind.tkCommt] := fCommtAttrib; fAttribLut[TTokenKind.tkKeywd] := fKeywdAttrib; fAttribLut[TTokenKind.tkNumbr] := fNumbrAttrib; fAttribLut[TTokenKind.tkStrng] := fStrngAttrib; fAttribLut[TTokenKind.tksymbl] := fSymblAttrib; fAttribLut[TTokenKind.tkAttri] := fAttriAttrib; fAttribLut[TTokenKind.tkError] := fErrorAttrib; end; destructor TSynSxSyn.destroy; begin fCurrRange.Free; inherited; end; function TSynSxSyn.GetRangeClass: TSynCustomHighlighterRangeClass; begin result := TSynSxSynRange; end; function TSynSxSyn.GetIdentChars: TSynIdentChars; begin result := ['_', 'A'..'Z', 'a'..'z', '0'..'9']; end; procedure TSynSxSyn.setWhiteAttrib(value: TSynHighlighterAttributes); begin fWhiteAttrib.Assign(value); end; procedure TSynSxSyn.setNumbrAttrib(value: TSynHighlighterAttributes); begin fNumbrAttrib.Assign(value); end; procedure TSynSxSyn.setSymblAttrib(value: TSynHighlighterAttributes); begin fSymblAttrib.Assign(value); end; procedure TSynSxSyn.setIdentAttrib(value: TSynHighlighterAttributes); begin fIdentAttrib.Assign(value); end; procedure TSynSxSyn.setCommtAttrib(value: TSynHighlighterAttributes); begin fCommtAttrib.Assign(value); end; procedure TSynSxSyn.setStrngAttrib(value: TSynHighlighterAttributes); begin fStrngAttrib.Assign(value); end; procedure TSynSxSyn.setKeywdAttrib(value: TSynHighlighterAttributes); begin fKeywdAttrib.Assign(value); end; procedure TSynSxSyn.setAttriAttrib(value: TSynHighlighterAttributes); begin fAttriAttrib.Assign(value); end; procedure TSynSxSyn.setErrorAttrib(value: TSynHighlighterAttributes); begin fErrorAttrib.Assign(value); end; function TSynSxSyn.GetTokenAttribute: TSynHighlighterAttributes; begin result := fAttribLut[fTokKind]; end; procedure TSynSxSyn.SetRange(value: Pointer); var stored: TSynSxSynRange; begin inherited SetRange(value); stored := TSynSxSynRange(CodeFoldRange.RangeType); if fCurrRange.isAssigned and stored.isAssigned then fCurrRange.copyFrom(stored); end; function TSynSxSyn.GetRange: Pointer; var stored: TSynSxSynRange; begin stored := TSynSxSynRange(inherited GetRange); if stored.isNotAssigned then stored := TSynSxSynRange.Create(nil); stored.copyFrom(fCurrRange); CodeFoldRange.RangeType := Pointer(stored); Result := inherited GetRange; end; procedure TSynSxSyn.ResetRange; begin if fCurrRange.isNotAssigned then fCurrRange := TSynSxSynRange.Create(nil) else fCurrRange.Clear; end; procedure TSynSxSyn.setLine(const NewValue: string; LineNumber: Integer); begin inherited; fLineBuf := NewValue; fLineNum := LineNumber; fTokStop := 1; next; end; function TSynSxSyn.GetEol: Boolean; begin result := fTokKind = tkNone; end; function TSynSxSyn.GetTokenPos: Integer; begin result := fTokStart - 1; end; function TSynSxSyn.GetToken: string; begin result := copy(fLineBuf, FTokStart, fTokStop - FTokStart); end; procedure TSynSxSyn.GetTokenEx(out TokenStart: PChar; out TokenLength: integer); begin TokenStart := @fLineBuf[FTokStart]; TokenLength := fTokStop - FTokStart; end; function TSynSxSyn.GetDefaultAttribute(Index: integer): TSynHighlighterAttributes; begin result := nil; end; function TSynSxSyn.GetTokenKind: integer; begin Result := Integer(fTokKind); end; function TSynSxSyn.safeLookupChar: PChar; begin if fTokStop >= length(fLineBuf) then result := nil else result := @fLineBuf[fTokStop + 1]; end; function TSynSxSyn.canLookup2Char(): boolean; begin result := fTokStop + 2 <= length(fLineBuf); end; procedure TSynSxSyn.lexOpAndOpEqual(); var nextPChar: PChar; nextChar: char; begin fTokKind := TTokenKind.tkSymbl; nextPChar := safeLookupChar(); if nextPChar <> nil then begin nextChar := nextPChar^; if nextChar = '=' then fTokStop += 1; end; fTokStop += 1; end; procedure TSynSxSyn.lexOpAndOpOpAndOpEqual(const op: char); var nextPChar: PChar; nextChar: char; begin fTokKind := TTokenKind.tkSymbl; nextPChar := safeLookupChar(); if nextPChar <> nil then begin nextChar := fLineBuf[fTokStop]; if (nextChar = op) or (nextChar = '=') then fTokStop += 1; end; fTokStop += 1; end; procedure TSynSxSyn.lexOpAndOpOpAndOpEqualAndOpOpEqual(const op: char); var nextPChar: PChar; nextChar: char; can2: boolean; begin fTokKind := TTokenKind.tkSymbl; can2 := canLookup2Char(); nextPChar := safeLookupChar(); // <<= if can2 and (fLineBuf[fTokStop + 1] = op) and (fLineBuf[fTokStop+2] = '=') then fTokStop += 2 else if nextPChar <> nil then begin nextChar := nextPChar^; // << or <= if (nextChar = op) or (nextChar = '=') then fTokStop += 1; end; fTokStop += 1; end; procedure TSynSxSyn.lexAssEquOrLambda(); var nextPChar: PChar; nextChar: char; begin fTokKind := TTokenKind.tkSymbl; nextPChar := safeLookupChar(); if nextPChar <> nil then begin nextChar := fLineBuf[fTokStop]; if (nextChar = '=') or (nextChar = '>') then fTokStop += 1; end; fTokStop += 1; end; procedure TSynSxSyn.lexIntLiteral(); var nextPChar: PChar; nextChar: char; begin fTokKind:=TTokenKind.tkNumbr; while fTokStop <= fLineBuf.length do begin case fLineBuf[fTokStop] of '0'..'9', '_': begin fTokStop += 1; continue; end; '.': begin nextPChar := safeLookupChar(); if nextPChar <> nil then begin nextChar := nextPChar^; if nextChar in ['0' .. '9'] then begin fTokStop += 1; lexFloatingLiteralFractionalPart(); exit; end; end; break; end; end; break; end; end; procedure TSynSxSyn.lexFloatingLiteralFractionalPart(); begin fTokKind:=TTokenKind.tkNumbr; while fTokStop <= fLineBuf.length do begin case fLineBuf[fTokStop] of '0'..'9', '_': fTokStop += 1; 'e', 'E': begin lexExponent(); exit; end else break; end; end; end; procedure TSynSxSyn.lexExponent(); begin fTokStop += 1; if fTokStop > fLineBuf.length then begin fTokKind:=TTokenKind.tkError; exit; end; if fLineBuf[fTokStop] in ['+', '-'] then fTokStop += 1; if fTokStop > fLineBuf.length then begin fTokKind:=TTokenKind.tkError; exit; end; while fTokStop <= fLineBuf.length do begin if fLineBuf[fTokStop] in ['0' .. '9'] then begin fTokStop += 1; continue; end else break; end; end; procedure TSynSxSyn.lexHexLiteral(); var firstChar: Boolean = false; begin fTokStop += 2; fTokKind:=TTokenKind.tkNumbr; while fTokStop <= fLineBuf.length do begin case fLineBuf[fTokStop] of '0'..'9', 'a'..'f', 'A'..'F', '_': begin if not firstChar and (fLineBuf[fTokStop] = '_') then fTokKind:=TTokenKind.tkError; fTokStop += 1; firstChar := true; continue; end else while (fTokStop <= fLineBuf.length) and (fLineBuf[fTokStop] in ['g' .. 'z', 'G' .. 'Z']) do begin fTokKind := TTokenKind.tkError; fTokStop += 1; end; end; break; end; end; procedure TSynSxSyn.lexBinLiteral(); var firstChar: Boolean = false; begin fTokStop += 2; fTokKind:=TTokenKind.tkNumbr; while fTokStop <= fLineBuf.length do begin case fLineBuf[fTokStop] of '0', '1', '_': begin if not firstChar and (fLineBuf[fTokStop] = '_') then fTokKind:=TTokenKind.tkError; fTokStop += 1; firstChar := true; continue; end; else while (fTokStop <= fLineBuf.length) and (fLineBuf[fTokStop] in ['2' .. '9', 'a' .. 'z', 'A' .. 'Z']) do begin fTokKind := TTokenKind.tkError; fTokStop += 1; end; end; break; end; end; procedure TSynSxSyn.lexStringLiteral(); var firstLine: Boolean; terminate: Boolean = false; begin fTokKind := TTokenKind.tkStrng; firstLine := fCurrRange.rangeKind = TRangeKind.rkNone; if firstLine then fTokStop += 1; while fTokStop <= fLineBuf.length do begin case fLineBuf[fTokStop] of '\' : fTokStop += 2; '"' : begin fTokStop += 1; terminate := true; break; end else fTokStop += 1; end; end; if firstLine and not terminate then fCurrRange.rangeKind:= TRangeKind.rkString1 else if (fCurrRange.rangeKind = TRangeKind.rkString1) and terminate then fCurrRange.rangeKind:= TRangeKind.rkNone; end; procedure TSynSxSyn.lexRawStringLiteral(); var firstLine: Boolean; terminate: Boolean = false; begin fTokKind := TTokenKind.tkStrng; firstLine := fCurrRange.rangeKind = TRangeKind.rkNone; if firstLine then fTokStop += 1; while fTokStop <= fLineBuf.length do begin if fLineBuf[fTokStop] = '`' then begin fTokStop += 1; terminate := true; break; end else fTokStop += 1; end; if firstLine and not terminate then fCurrRange.rangeKind:= TRangeKind.rkString2 else if (fCurrRange.rangeKind = TRangeKind.rkString2) and terminate then fCurrRange.rangeKind:= TRangeKind.rkNone; end; procedure TSynSxSyn.lexLineComment(); begin fTokKind := TTokenKind.tkCommt; fTokStop := fLineBuf.length + 1; end; procedure TSynSxSyn.lexStarComment(); var firstLine: Boolean; terminate: Boolean = false; begin fTokKind := TTokenKind.tkCommt; firstLine := fCurrRange.rangeKind = TRangeKind.rkNone; while fTokStop <= fLineBuf.length do begin if fLineBuf[fTokStop] = '*' then begin fTokStop += 1; if (fTokStop <= fLineBuf.length) and (fLineBuf[fTokStop] = '/') then begin fTokStop += 1; terminate := true; break; end; end else fTokStop += 1; end; if firstLine and not terminate then fCurrRange.rangeKind := TRangeKind.rkBlockCom1 else if (fCurrRange.rangeKind = TRangeKind.rkBlockCom1) and terminate then fCurrRange.rangeKind := TRangeKind.rkNone; end; procedure TSynSxSyn.lexIdentifier(); var dollar: boolean; oneChr: boolean = false; begin fTokKind := TTokenKind.tkIdent; dollar := fLineBuf[fTokStop] = '$'; if dollar then fTokStop += 1; while fTokStop <= fLineBuf.length do begin case fLineBuf[fTokStop] of '_', 'a'..'z', 'A'..'Z': begin oneChr := true; fTokStop += 1; continue; end; '0' .. '9': begin if oneChr then begin fTokStop += 1; continue; end else break; // e.g $0 end else break; end; end; if dollar and not oneChr then fTokKind := TTokenKind.tkError else begin if KeywordMatch.contains(GetToken()) then fTokKind := TTokenKind.tkKeywd; end; end; procedure TSynSxSyn.next; var llen: integer; nextPChar: PChar; nextChar: char; begin fTokKind := tkNone; fTokStart := fTokStop; llen := length(fLineBuf); // EOL if fTokStop > llen then exit; // continue partial multi-line ranges if fCurrRange.isNotAssigned then fCurrRange := TSynSxSynRange.Create(nil) else case fCurrRange.rangeKind of TRangeKind.rkString1: begin lexStringLiteral(); exit; end; TRangeKind.rkString2: begin lexRawStringLiteral(); exit; end; TRangeKind.rkBlockCom1: begin lexStarComment(); exit; end; end; // special lines if (fLineBuf.length > 1) then begin // she bang if (fLineNum = 0) and (fLineBuf[1..2] = '#!') then begin lexLineComment(); exit; end // "ยง" of SAR else if (fTokStart = 1) and (fLineBuf[1..2] = #194#167) then begin lexLineComment(); exit; end; end; case fLineBuf[fTokStop] of #0 .. #10, #13, #32: begin fTokStop += 1; fTokKind := TTokenKind.tkBlank; end; // `//comment` `/*comment` `/=` `/` '/': begin fTokKind := TTokenKind.tkSymbl; fTokStop += 1; if (fTokStop <= llen) then case fLineBuf[fTokStop] of '/' : lexLineComment(); '*' : begin fTokStop += 1; lexStarComment(); end; '=' : fTokStop += 1; end; end; // `_ident` `$kwIdent` 'a'..'z', 'A'..'Z', '_', '$': lexIdentifier(); // `0x...` `0b...` `012...` `0.12...` `012...` '0': begin nextPChar := safeLookupChar(); if nextPChar <> nil then begin nextChar := nextPChar^; if (nextChar = 'x') or (nextChar = 'X') then lexHexLiteral() else if (nextChar = 'b') or (nextChar = 'B') then lexBinLiteral() else lexIntLiteral(); end else lexIntLiteral(); end; // number '1' .. '9' : lexIntLiteral(); // "string" '"': lexStringLiteral(); // `string` '`': lexRawStringLiteral(); // `-` `-=` `--` '-': lexOpAndOpOpAndOpEqual('-'); // `&` `&=` `&&` '&': lexOpAndOpOpAndOpEqual('&'); // `|` `|=` `||` '|': lexOpAndOpOpAndOpEqual('|'); // `+` `+=` `++` '+': lexOpAndOpOpAndOpEqual('+'); // `*` `*=` `%` `%=` `^` `^=` `~` `~=` `!` `!=` '*', '%', '^', '!', '~': lexOpAndOpEqual(); // `<` `<<` `<=` `<<=` `>` `>>` `>=` `>>=` '<': lexOpAndOpOpAndOpEqualAndOpOpEqual('<'); '>': lexOpAndOpOpAndOpEqualAndOpOpEqual('>'); // `=`, `==`, `=>` '=': lexAssEquOrLambda(); '.', '(', ')', ',', ':' , '[', ']', '?', ';' : begin fTokKind := TTokenKind.tkSymbl; fTokStop += 1; end; '@': begin fTokKind := TTokenKind.tkError; fTokStop += 1; if fTokStop <= llen then begin lexIdentifier(); fTokKind := TTokenKind.tkAttri; end; end; '{': begin fTokKind := TTokenKind.tkSymbl; fTokStop += 1; StartCodeFoldBlock(); end; '}': begin fTokKind := TTokenKind.tkSymbl; fTokStop += 1; EndCodeFoldBlock(); end else begin fTokStop += 1; fTokKind := TTokenKind.tkError; end; end; end; end.