mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 10:57:55 +02:00
1250 lines
32 KiB
ObjectPascal
1250 lines
32 KiB
ObjectPascal
{-------------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: SynHighlighterPython.pas, released 2000-06-23.
|
|
The Original Code is based on the odPySyn.pas file from the
|
|
mwEdit component suite by Martin Waldenburg and other developers, the Initial
|
|
Author of this file is Olivier Deckmyn.
|
|
Portions created by M.Utku Karatas and Dennis Chuah.
|
|
All Rights Reserved.
|
|
|
|
Contributors to the SynEdit and mwEdit projects are listed in the
|
|
Contributors.txt file.
|
|
|
|
Alternatively, the contents of this file may be used under the terms of the
|
|
GNU General Public License Version 2 or later (the "GPL"), in which case
|
|
the provisions of the GPL are applicable instead of those above.
|
|
If you wish to allow use of your version of this file only under the terms
|
|
of the GPL and not to allow others to use your version of this file
|
|
under the MPL, indicate your decision by deleting the provisions above and
|
|
replace them with the notice and other provisions required by the GPL.
|
|
If you do not delete the provisions above, a recipient may use your version
|
|
of this file under either the MPL or the GPL.
|
|
|
|
$Id$
|
|
|
|
You may retrieve the latest version of this file at the SynEdit home page,
|
|
located at http://SynEdit.SourceForge.net
|
|
|
|
Known Issues:
|
|
-------------------------------------------------------------------------------}
|
|
{
|
|
@abstract(A Python language highlighter for SynEdit)
|
|
@author(Olivier Deckmyn, converted to SynEdit by David Muir <dhmn@dmsoftware.co.uk>)
|
|
@created(unknown, converted to SynEdit on 2000-06-23)
|
|
@lastmod(2003-02-13)
|
|
The SynHighlighterPython implements a highlighter for Python for the SynEdit projects.
|
|
}
|
|
unit SynHighlighterPython;
|
|
|
|
{$I SynEdit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
IniFiles, //THashedStringList
|
|
LCLIntf, LCLType,
|
|
SynEditHighlighter, SynEditTypes, SynEditStrConst,
|
|
Graphics, SysUtils, Classes;
|
|
|
|
const
|
|
ALPHA_CHARS = ['_', 'a'..'z', 'A'..'Z'];
|
|
IDENTIFIER_CHARS = ['0'..'9'] + ALPHA_CHARS;
|
|
|
|
type
|
|
TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
|
|
tkString, tkSymbol, tkNonKeyword, tkTripleQuotedString,
|
|
tkSystemDefined, tkHex, tkOct, tkFloat, tkUnknown);
|
|
|
|
TRangeState = (rsANil, rsComment, rsUnKnown, rsMultilineString, rsMultilineString2,
|
|
rsMultilineString3 //this is to indicate if a string is made multiline by backslash char at line end (as in C++ highlighter)
|
|
);
|
|
|
|
TProcTableProc = procedure of object;
|
|
|
|
type
|
|
TSynPythonSyn = class(TSynCustomHighLighter)
|
|
private
|
|
fStringStarter: char; // used only for rsMultilineString3 stuff
|
|
fRange: TRangeState;
|
|
fLine: PChar;
|
|
fLineNumber: Integer;
|
|
fProcTable: array[#0..#255] of TProcTableProc;
|
|
fToIdent: PChar;
|
|
fTokenPos: Integer;
|
|
FTokenID: TtkTokenKind;
|
|
FKeywords: TStringList;
|
|
|
|
fStringAttri: TSynHighlighterAttributes;
|
|
fDocStringAttri: TSynHighlighterAttributes;
|
|
fNumberAttri: TSynHighlighterAttributes;
|
|
fHexAttri: TSynHighlighterAttributes;
|
|
fOctalAttri: TSynHighlighterAttributes;
|
|
fFloatAttri: TSynHighlighterAttributes;
|
|
fKeyAttri: TSynHighlighterAttributes;
|
|
fNonKeyAttri: TSynHighlighterAttributes;
|
|
fSystemAttri: TSynHighlighterAttributes;
|
|
fSymbolAttri: TSynHighlighterAttributes;
|
|
fCommentAttri: TSynHighlighterAttributes;
|
|
fIdentifierAttri: TSynHighlighterAttributes;
|
|
fSpaceAttri: TSynHighlighterAttributes;
|
|
fErrorAttri: TSynHighlighterAttributes;
|
|
|
|
procedure SymbolProc;
|
|
procedure CRProc;
|
|
procedure CommentProc;
|
|
procedure GreaterProc;
|
|
procedure IdentProc;
|
|
procedure LFProc;
|
|
procedure LowerProc;
|
|
procedure NullProc;
|
|
procedure NumberProc;
|
|
procedure SpaceProc;
|
|
procedure PreStringProc;
|
|
procedure UnicodeStringProc;
|
|
procedure StringProc;
|
|
procedure String2Proc;
|
|
procedure StringEndProc(EndChar:char);
|
|
procedure UnknownProc;
|
|
procedure MakeMethodTables;
|
|
|
|
protected
|
|
Run: LongInt;
|
|
fStringLen: Integer;
|
|
|
|
function GetIdentChars: TSynIdentChars; override;
|
|
function GetSampleSource: string; override;
|
|
function IdentKind(MayBe: PChar): TtkTokenKind; virtual;
|
|
property Keywords: TStringlist read FKeywords;
|
|
property TokenID: TtkTokenKind read FTokenID;
|
|
|
|
public
|
|
class function GetLanguageName: string; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function GetDefaultAttribute(Index: integer): TSynHighlighterAttributes;
|
|
override;
|
|
function GetEol: Boolean; override;
|
|
function GetRange: Pointer; override;
|
|
function GetTokenID: TtkTokenKind;
|
|
procedure SetLine(const NewValue: string;
|
|
LineNumber: Integer); override;
|
|
function GetKeywordIdentifiers: TStringList; virtual;
|
|
function GetToken: string; override;
|
|
function GetTokenAttribute: TSynHighlighterAttributes; override;
|
|
function GetTokenKind: integer; override;
|
|
function GetTokenPos: Integer; override;
|
|
procedure Next; override;
|
|
property IdentChars;
|
|
procedure SetRange(Value: Pointer); override;
|
|
procedure ResetRange; override;
|
|
procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
|
|
published
|
|
property CommentAttri: TSynHighlighterAttributes read fCommentAttri
|
|
write fCommentAttri;
|
|
property IdentifierAttri: TSynHighlighterAttributes read fIdentifierAttri
|
|
write fIdentifierAttri;
|
|
property KeyAttri: TSynHighlighterAttributes read fKeyAttri write fKeyAttri;
|
|
property NonKeyAttri: TSynHighlighterAttributes read fNonKeyAttri
|
|
write fNonKeyAttri;
|
|
property SystemAttri: TSynHighlighterAttributes read fSystemAttri
|
|
write fSystemAttri;
|
|
property NumberAttri: TSynHighlighterAttributes read fNumberAttri
|
|
write fNumberAttri;
|
|
property HexAttri: TSynHighlighterAttributes read fHexAttri
|
|
write fHexAttri;
|
|
property OctalAttri: TSynHighlighterAttributes read fOctalAttri
|
|
write fOctalAttri;
|
|
property FloatAttri: TSynHighlighterAttributes read fFloatAttri
|
|
write fFloatAttri;
|
|
property SpaceAttri: TSynHighlighterAttributes read fSpaceAttri
|
|
write fSpaceAttri;
|
|
property StringAttri: TSynHighlighterAttributes read fStringAttri
|
|
write fStringAttri;
|
|
property DocStringAttri: TSynHighlighterAttributes read fDocStringAttri
|
|
write fDocStringAttri;
|
|
property SymbolAttri: TSynHighlighterAttributes read fSymbolAttri
|
|
write fSymbolAttri;
|
|
property ErrorAttri: TSynHighlighterAttributes read fErrorAttri
|
|
write fErrorAttri;
|
|
end;
|
|
|
|
implementation
|
|
|
|
var
|
|
GlobalKeywords: TStringList;
|
|
|
|
function TSynPythonSyn.GetKeywordIdentifiers: TStringList;
|
|
const
|
|
// No need to localise keywords!
|
|
|
|
// List of keywords
|
|
KEYWORDCOUNT = 35;
|
|
KEYWORDSIdents: array [1..KEYWORDCOUNT] of string =
|
|
(
|
|
'as',
|
|
'and',
|
|
'assert',
|
|
'async',
|
|
'await',
|
|
'break',
|
|
'class',
|
|
'continue',
|
|
'def',
|
|
'del',
|
|
'elif',
|
|
'else',
|
|
'except',
|
|
'False',
|
|
'finally',
|
|
'for',
|
|
'from',
|
|
'global',
|
|
'if',
|
|
'import',
|
|
'in',
|
|
'is',
|
|
'lambda',
|
|
'None',
|
|
'nonlocal',
|
|
'not',
|
|
'or',
|
|
'pass',
|
|
'raise',
|
|
'return',
|
|
'True',
|
|
'try',
|
|
'while',
|
|
'with',
|
|
'yield'
|
|
);
|
|
|
|
// List of non-keyword identifiers
|
|
NONKEYWORDCOUNT = 78;
|
|
NONKEYWORDS: array [1..NONKEYWORDCOUNT] of string =
|
|
(
|
|
'__future__',
|
|
'__import__',
|
|
'abs',
|
|
'aiter',
|
|
'all',
|
|
'anext',
|
|
'any',
|
|
'ascii',
|
|
'bin',
|
|
'bool',
|
|
'breakpoint',
|
|
'bytearray',
|
|
'bytes',
|
|
'callable',
|
|
'chr',
|
|
'classmethod',
|
|
'compile',
|
|
'complex',
|
|
'copyright',
|
|
'credits',
|
|
'delattr',
|
|
'dict',
|
|
'dir',
|
|
'divmod',
|
|
'enumerate',
|
|
'eval',
|
|
'exec',
|
|
'exit',
|
|
'filter',
|
|
'float',
|
|
'format',
|
|
'frozenset',
|
|
'getattr',
|
|
'globals',
|
|
'hasattr',
|
|
'hash',
|
|
'help',
|
|
'hex',
|
|
'id',
|
|
'input',
|
|
'int',
|
|
'isinstance',
|
|
'issubclass',
|
|
'iter',
|
|
'len',
|
|
'license',
|
|
'list',
|
|
'locals',
|
|
'map',
|
|
'max',
|
|
'memoryview',
|
|
'min',
|
|
'next',
|
|
'NotImplemented',
|
|
'object',
|
|
'oct',
|
|
'open',
|
|
'ord',
|
|
'pow',
|
|
'print',
|
|
'property',
|
|
'quit',
|
|
'range',
|
|
'repr',
|
|
'reversed',
|
|
'round',
|
|
'set',
|
|
'setattr',
|
|
'slice',
|
|
'sorted',
|
|
'staticmethod',
|
|
'str',
|
|
'sum',
|
|
'super',
|
|
'tuple',
|
|
'type',
|
|
'vars',
|
|
'zip'
|
|
);
|
|
var
|
|
f: Integer;
|
|
begin
|
|
if not Assigned (GlobalKeywords) then begin
|
|
// Create the string list of keywords - only once
|
|
GlobalKeywords := TStringList.Create;
|
|
|
|
for f := 1 to KEYWORDCOUNT do
|
|
GlobalKeywords.AddObject (KEYWORDSIdents[f],
|
|
TObject(Ord(tkKey)));
|
|
for f := 1 to NONKEYWORDCOUNT do
|
|
GlobalKeywords.AddObject (NONKEYWORDS[f],
|
|
TObject(Ord(tkNonKeyword)));
|
|
end; // if
|
|
Result := GlobalKeywords;
|
|
end;
|
|
|
|
function TSynPythonSyn.IdentKind(MayBe: PChar): TtkTokenKind;
|
|
var
|
|
index: Integer;
|
|
temp: PChar;
|
|
s: string;
|
|
|
|
begin
|
|
// Extract the identifier out - it is assumed to terminate in a
|
|
// non-alphanumeric character
|
|
fToIdent := MayBe;
|
|
temp := MayBe;
|
|
while temp^ in IDENTIFIER_CHARS do
|
|
Inc (temp);
|
|
fStringLen := temp - fToIdent;
|
|
|
|
// Check to see if it is a keyword
|
|
SetString (s, fToIdent, fStringLen);
|
|
index := FKeywords.IndexOf (s);
|
|
|
|
if index <> -1 then
|
|
Result := TtkTokenKind (PtrInt(FKeywords.Objects[index]))
|
|
|
|
// Check if it is a system identifier (__*__)
|
|
else if (fStringLen >= 5) and
|
|
(MayBe[0] = '_') and (MayBe[1] = '_') and (MayBe[2] <> '_') and
|
|
(MayBe[fStringLen-1] = '_') and (MayBe[fStringLen-2] = '_') and
|
|
(MayBe[fStringLen-3] <> '_') then
|
|
Result := tkSystemDefined
|
|
|
|
// Else, hey, it is an ordinary run-of-the-mill identifier!
|
|
else
|
|
Result := tkIdentifier;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.MakeMethodTables;
|
|
var
|
|
I: Char;
|
|
begin
|
|
for I := #0 to #255 do
|
|
case I of
|
|
'&', '}', '{', ':', ',', ']', '[', '*', '`',
|
|
'^', ')', '(', ';', '/', '=', '-', '+', '!', '\',
|
|
'%', '|', '~' :
|
|
fProcTable[I] := @SymbolProc;
|
|
#13: fProcTable[I] := @CRProc;
|
|
'#': fProcTable[I] := @CommentProc;
|
|
'>': fProcTable[I] := @GreaterProc;
|
|
'A'..'Q', 'S', 'T', 'V'..'Z', 'a'..'q', 's', 't', 'v'..'z', '_': fProcTable[I] := @IdentProc;
|
|
#10: fProcTable[I] := @LFProc;
|
|
'<': fProcTable[I] := @LowerProc;
|
|
#0: fProcTable[I] := @NullProc;
|
|
'.', '0'..'9': fProcTable[I] := @NumberProc;
|
|
#1..#9, #11, #12, #14..#32:
|
|
fProcTable[I] := @SpaceProc;
|
|
'r', 'R': fProcTable[I] := @PreStringProc;
|
|
'u', 'U': fProcTable[I] := @UnicodeStringProc;
|
|
'''': fProcTable[I] := @StringProc;
|
|
'"': fProcTable[I] := @String2Proc;
|
|
else
|
|
fProcTable[I] := @UnknownProc;
|
|
end;
|
|
end;
|
|
|
|
constructor TSynPythonSyn.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
|
|
FKeywords := THashedStringList.Create;
|
|
FKeywords.CaseSensitive := True;
|
|
FKeywords.Duplicates := dupError;
|
|
FKeywords.Assign (GetKeywordIdentifiers);
|
|
|
|
fRange := rsUnknown;
|
|
fCommentAttri := TSynHighlighterAttributes.Create(@SYNS_AttrComment, SYNS_XML_AttrComment);
|
|
fCommentAttri.Foreground := clGray;
|
|
fCommentAttri.Style := [fsItalic];
|
|
AddAttribute(fCommentAttri);
|
|
fIdentifierAttri := TSynHighlighterAttributes.Create(@SYNS_AttrIdentifier, SYNS_XML_AttrIdentifier);
|
|
AddAttribute(fIdentifierAttri);
|
|
fKeyAttri := TSynHighlighterAttributes.Create(@SYNS_AttrReservedWord, SYNS_XML_AttrReservedWord);
|
|
fKeyAttri.Style := [fsBold];
|
|
AddAttribute(fKeyAttri);
|
|
fNonKeyAttri := TSynHighlighterAttributes.Create(@SYNS_AttrNonReservedKeyword, SYNS_XML_AttrNonReservedKeyword);
|
|
fNonKeyAttri.Foreground := clNavy;
|
|
fNonKeyAttri.Style := [fsBold];
|
|
AddAttribute (fNonKeyAttri);
|
|
fSystemAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSystem, SYNS_XML_AttrSystem);
|
|
fSystemAttri.Style := [fsBold];
|
|
AddAttribute (fSystemAttri);
|
|
fNumberAttri := TSynHighlighterAttributes.Create(@SYNS_AttrNumber, SYNS_XML_AttrNumber);
|
|
fNumberAttri.Foreground := clBlue;
|
|
AddAttribute(fNumberAttri);
|
|
fHexAttri := TSynHighlighterAttributes.Create(@SYNS_AttrHexadecimal, SYNS_XML_AttrHexadecimal);
|
|
fHexAttri.Foreground := clBlue;
|
|
AddAttribute(fHexAttri);
|
|
fOctalAttri := TSynHighlighterAttributes.Create(@SYNS_AttrOctal, SYNS_XML_AttrOctal);
|
|
fOctalAttri.Foreground := clBlue;
|
|
AddAttribute(fOctalAttri);
|
|
fFloatAttri := TSynHighlighterAttributes.Create(@SYNS_AttrFloat, SYNS_XML_AttrFloat);
|
|
fFloatAttri.Foreground := clBlue;
|
|
AddAttribute(fFloatAttri);
|
|
fSpaceAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSpace, SYNS_XML_AttrSpace);
|
|
AddAttribute(fSpaceAttri);
|
|
fStringAttri := TSynHighlighterAttributes.Create(@SYNS_AttrString, SYNS_XML_AttrString);
|
|
fStringAttri.Foreground := clBlue;
|
|
AddAttribute(fStringAttri);
|
|
fDocStringAttri := TSynHighlighterAttributes.Create(@SYNS_AttrDocumentation, SYNS_XML_AttrDocumentation);
|
|
fDocStringAttri.Foreground := clTeal;
|
|
AddAttribute(fDocStringAttri);
|
|
fSymbolAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSymbol, SYNS_XML_AttrSymbol);
|
|
AddAttribute(fSymbolAttri);
|
|
fErrorAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSyntaxError, SYNS_XML_AttrSyntaxError);
|
|
fErrorAttri.Foreground := clRed;
|
|
AddAttribute(fErrorAttri);
|
|
SetAttributesOnChange(@DefHighlightChange);
|
|
MakeMethodTables;
|
|
fDefaultFilter := SYNS_FilterPython;
|
|
end; { Create }
|
|
|
|
destructor TSynPythonSyn.Destroy;
|
|
begin
|
|
FKeywords.Free;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.SetLine(const NewValue: string;
|
|
LineNumber: Integer);
|
|
begin
|
|
inherited;
|
|
fLine := PChar(NewValue);
|
|
Run := 0;
|
|
fLineNumber := LineNumber;
|
|
Next;
|
|
end; { SetLine }
|
|
|
|
procedure TSynPythonSyn.GetTokenEx(out TokenStart: PChar;
|
|
out TokenLength: integer);
|
|
begin
|
|
TokenLength:=Run-fTokenPos;
|
|
TokenStart:=FLine + fTokenPos;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.SymbolProc;
|
|
begin
|
|
inc(Run);
|
|
fTokenID := tkSymbol;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.CRProc;
|
|
begin
|
|
fTokenID := tkSpace;
|
|
case FLine[Run + 1] of
|
|
#10: inc(Run, 2);
|
|
else
|
|
inc(Run);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.CommentProc;
|
|
begin
|
|
fTokenID := tkComment;
|
|
inc(Run);
|
|
while not (FLine[Run] in [#13, #10, #0]) do
|
|
inc(Run);
|
|
end;
|
|
|
|
procedure TSynPythonSyn.GreaterProc;
|
|
begin
|
|
case FLine[Run + 1] of
|
|
'=': begin
|
|
inc(Run, 2);
|
|
fTokenID := tkSymbol;
|
|
end;
|
|
else begin
|
|
inc(Run);
|
|
fTokenID := tkSymbol;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.IdentProc;
|
|
begin
|
|
fTokenID := IdentKind((fLine + Run));
|
|
inc(Run, fStringLen);
|
|
end;
|
|
|
|
procedure TSynPythonSyn.LFProc;
|
|
begin
|
|
fTokenID := tkSpace;
|
|
inc(Run);
|
|
end;
|
|
|
|
procedure TSynPythonSyn.LowerProc;
|
|
begin
|
|
case FLine[Run + 1] of
|
|
'=': begin
|
|
inc(Run, 2);
|
|
fTokenID := tkSymbol;
|
|
end;
|
|
'>': begin
|
|
inc(Run, 2);
|
|
fTokenID := tkSymbol;
|
|
end
|
|
else begin
|
|
inc(Run);
|
|
fTokenID := tkSymbol;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.NullProc;
|
|
begin
|
|
fTokenID := tkNull;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.NumberProc;
|
|
const
|
|
INTCHARS = ['0' .. '9'];
|
|
HEXCHARS = ['a' .. 'f', 'A' .. 'F'] + INTCHARS;
|
|
OCTCHARS = ['0' .. '7'];
|
|
HEXINDICATOR = ['x', 'X'];
|
|
LONGINDICATOR = ['l', 'L'];
|
|
IMAGINARYINDICATOR = ['j', 'J'];
|
|
EXPONENTINDICATOR = ['e', 'E'];
|
|
EXPONENTSIGN = ['+', '-'];
|
|
DOT = '.';
|
|
ZERO = '0';
|
|
|
|
type
|
|
TNumberState =
|
|
(
|
|
nsStart,
|
|
nsDotFound,
|
|
nsFloatNeeded,
|
|
nsHex,
|
|
nsOct,
|
|
nsExpFound
|
|
);
|
|
|
|
var
|
|
temp: Char;
|
|
State: TNumberState;
|
|
|
|
function CheckSpecialCases: Boolean;
|
|
begin
|
|
case temp of
|
|
// Look for dot (.)
|
|
DOT: begin
|
|
// .45
|
|
if FLine[Run] in INTCHARS then begin
|
|
Inc (Run);
|
|
fTokenID := tkFloat;
|
|
State := nsDotFound;
|
|
|
|
// Non-number dot
|
|
end else begin
|
|
// Ellipsis
|
|
if (FLine[Run] = DOT) and (FLine[Run+1] = DOT) then
|
|
Inc (Run, 2);
|
|
fTokenID := tkSymbol;
|
|
Result := False;
|
|
Exit;
|
|
end; // if
|
|
end; // DOT
|
|
|
|
// Look for zero (0)
|
|
ZERO: begin
|
|
temp := FLine[Run];
|
|
// 0x123ABC
|
|
if temp in HEXINDICATOR then begin
|
|
Inc (Run);
|
|
fTokenID := tkHex;
|
|
State := nsHex;
|
|
// 0.45
|
|
end else if temp = DOT then begin
|
|
Inc (Run);
|
|
State := nsDotFound;
|
|
fTokenID := tkFloat;
|
|
end else if temp in INTCHARS then begin
|
|
Inc (Run);
|
|
// 0123 or 0123.45
|
|
if temp in OCTCHARS then begin
|
|
fTokenID := tkOct;
|
|
State := nsOct;
|
|
// 0899.45
|
|
end else begin
|
|
fTokenID := tkFloat;
|
|
State := nsFloatNeeded;
|
|
end; // if
|
|
end; // if
|
|
end; // ZERO
|
|
end; // case
|
|
|
|
Result := True;
|
|
end; // CheckSpecialCases
|
|
|
|
function HandleBadNumber: Boolean;
|
|
begin
|
|
Result := False;
|
|
fTokenID := tkUnknown;
|
|
// Ignore all tokens till end of "number"
|
|
while FLine[Run] in (IDENTIFIER_CHARS + ['.']) do
|
|
Inc (Run);
|
|
end; // HandleBadNumber
|
|
|
|
function HandleExponent: Boolean;
|
|
begin
|
|
State := nsExpFound;
|
|
fTokenID := tkFloat;
|
|
// Skip e[+/-]
|
|
if FLine[Run+1] in EXPONENTSIGN then
|
|
Inc (Run);
|
|
// Invalid token : 1.0e
|
|
if not (FLine[Run+1] in INTCHARS) then begin
|
|
Inc (Run);
|
|
Result := HandleBadNumber;
|
|
Exit;
|
|
end; // if
|
|
|
|
Result := True;
|
|
end; // HandleExponent
|
|
|
|
function HandleDot: Boolean;
|
|
begin
|
|
// Check for ellipsis
|
|
Result := (FLine[Run+1] <> DOT) or (FLine[Run+2] <> DOT);
|
|
if Result then begin
|
|
State := nsDotFound;
|
|
fTokenID := tkFloat;
|
|
end; // if
|
|
end; // HandleDot
|
|
|
|
function CheckStart: Boolean;
|
|
begin
|
|
// 1234
|
|
if temp in INTCHARS then begin
|
|
Result := True;
|
|
//123e4
|
|
end else if temp in EXPONENTINDICATOR then begin
|
|
Result := HandleExponent;
|
|
// 123.45j
|
|
end else if temp in IMAGINARYINDICATOR then begin
|
|
Inc (Run);
|
|
fTokenID := tkFloat;
|
|
Result := False;
|
|
// 123.45
|
|
end else if temp = DOT then begin
|
|
Result := HandleDot;
|
|
// Error!
|
|
end else if temp in IDENTIFIER_CHARS then begin
|
|
Result := HandleBadNumber;
|
|
// End of number
|
|
end else begin
|
|
Result := False;
|
|
end; // if
|
|
end; // CheckStart
|
|
|
|
function CheckDotFound: Boolean;
|
|
begin
|
|
// 1.0e4
|
|
if temp in EXPONENTINDICATOR then begin
|
|
Result := HandleExponent;
|
|
// 123.45
|
|
end else if temp in INTCHARS then begin
|
|
Result := True;
|
|
// 123.45j
|
|
end else if temp in IMAGINARYINDICATOR then begin
|
|
Inc (Run);
|
|
Result := False;
|
|
// 123.45.45: Error!
|
|
end else if temp = DOT then begin
|
|
Result := False;
|
|
if HandleDot then
|
|
HandleBadNumber;
|
|
// Error!
|
|
end else if temp in IDENTIFIER_CHARS then begin
|
|
Result := HandleBadNumber;
|
|
// End of number
|
|
end else begin
|
|
Result := False;
|
|
end; // if
|
|
end; // CheckDotFound
|
|
|
|
function CheckFloatNeeded: Boolean;
|
|
begin
|
|
// 091.0e4
|
|
if temp in EXPONENTINDICATOR then begin
|
|
Result := HandleExponent;
|
|
// 0912345
|
|
end else if temp in INTCHARS then begin
|
|
Result := True;
|
|
// 09123.45
|
|
end else if temp = DOT then begin
|
|
Result := HandleDot or HandleBadNumber; // Bad octal
|
|
// 09123.45j
|
|
end else if temp in IMAGINARYINDICATOR then begin
|
|
Inc (Run);
|
|
Result := False;
|
|
// End of number (error: Bad oct number) 0912345
|
|
end else begin
|
|
Result := HandleBadNumber;
|
|
end;
|
|
end; // CheckFloatNeeded
|
|
|
|
function CheckHex: Boolean;
|
|
begin
|
|
// 0x123ABC
|
|
if temp in HEXCHARS then begin
|
|
Result := True;
|
|
// 0x123ABCL
|
|
end else if temp in LONGINDICATOR then begin
|
|
Inc (Run);
|
|
Result := False;
|
|
// 0x123.45: Error!
|
|
end else if temp = DOT then begin
|
|
Result := False;
|
|
if HandleDot then
|
|
HandleBadNumber;
|
|
// Error!
|
|
end else if temp in IDENTIFIER_CHARS then begin
|
|
Result := HandleBadNumber;
|
|
// End of number
|
|
end else begin
|
|
Result := False;
|
|
end; // if
|
|
end; // CheckHex
|
|
|
|
function CheckOct: Boolean;
|
|
begin
|
|
// 012345
|
|
if temp in INTCHARS then begin
|
|
if not (temp in OCTCHARS) then begin
|
|
State := nsFloatNeeded;
|
|
fTokenID := tkFloat;
|
|
end; // if
|
|
Result := True;
|
|
// 012345L
|
|
end else if temp in LONGINDICATOR then begin
|
|
Inc (Run);
|
|
Result := False;
|
|
// 0123e4
|
|
end else if temp in EXPONENTINDICATOR then begin
|
|
Result := HandleExponent;
|
|
// 0123j
|
|
end else if temp in IMAGINARYINDICATOR then begin
|
|
Inc (Run);
|
|
fTokenID := tkFloat;
|
|
Result := False;
|
|
// 0123.45
|
|
end else if temp = DOT then begin
|
|
Result := HandleDot;
|
|
// Error!
|
|
end else if temp in IDENTIFIER_CHARS then begin
|
|
Result := HandleBadNumber;
|
|
// End of number
|
|
end else begin
|
|
Result := False;
|
|
end; // if
|
|
end; // CheckOct
|
|
|
|
function CheckExpFound: Boolean;
|
|
begin
|
|
// 1e+123
|
|
if temp in INTCHARS then begin
|
|
Result := True;
|
|
// 1e+123j
|
|
end else if temp in IMAGINARYINDICATOR then begin
|
|
Inc (Run);
|
|
Result := False;
|
|
// 1e4.5: Error!
|
|
end else if temp = DOT then begin
|
|
Result := False;
|
|
if HandleDot then
|
|
HandleBadNumber;
|
|
// Error!
|
|
end else if temp in IDENTIFIER_CHARS then begin
|
|
Result := HandleBadNumber;
|
|
// End of number
|
|
end else begin
|
|
Result := False;
|
|
end; // if
|
|
end; // CheckExpFound
|
|
|
|
begin
|
|
State := nsStart;
|
|
fTokenID := tkNumber;
|
|
|
|
temp := FLine[Run];
|
|
Inc (Run);
|
|
|
|
// Special cases
|
|
if not CheckSpecialCases then
|
|
Exit;
|
|
|
|
// Use a state machine to parse numbers
|
|
while True do begin
|
|
temp := FLine[Run];
|
|
|
|
case State of
|
|
nsStart:
|
|
if not CheckStart then Exit;
|
|
nsDotFound:
|
|
if not CheckDotFound then Exit;
|
|
nsFloatNeeded:
|
|
if not CheckFloatNeeded then Exit;
|
|
nsHex:
|
|
if not CheckHex then Exit;
|
|
nsOct:
|
|
if not CheckOct then Exit;
|
|
nsExpFound:
|
|
if not CheckExpFound then Exit;
|
|
end; // case
|
|
|
|
Inc (Run);
|
|
end; // while
|
|
|
|
{
|
|
begin
|
|
while FLine[Run] in ['0'..'9', '.', 'e', 'E'] do begin
|
|
case FLine[Run] of
|
|
'.':
|
|
if FLine[Run + 1] = '.' then break;
|
|
end;
|
|
inc(Run);
|
|
end;
|
|
}
|
|
end;
|
|
|
|
procedure TSynPythonSyn.SpaceProc;
|
|
begin
|
|
inc(Run);
|
|
fTokenID := tkSpace;
|
|
while FLine[Run] in [#1..#9, #11, #12, #14..#32] do
|
|
inc(Run);
|
|
end;
|
|
|
|
procedure TSynPythonSyn.String2Proc;
|
|
var fBackslashCount:integer;
|
|
begin
|
|
fTokenID := tkString;
|
|
if (FLine[Run + 1] = '"') and (FLine[Run + 2] = '"') then begin
|
|
fTokenID := tkTripleQuotedString;
|
|
inc(Run, 3);
|
|
|
|
fRange:=rsMultilineString2;
|
|
while fLine[Run] <> #0 do begin
|
|
case fLine[Run] of
|
|
|
|
'\':begin
|
|
{ If we're looking at a backslash, and the following character is an
|
|
end quote, and it's preceeded by an odd number of backslashes, then
|
|
it shouldn't mark the end of the string. If it's preceeded by an
|
|
even number, then it should. !!!THIS RULE DOESNT APPLY IN RAW STRINGS}
|
|
if FLine[Run + 1] = '"' then
|
|
begin
|
|
fBackslashCount := 1;
|
|
|
|
while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
|
|
fBackslashCount := fBackslashCount + 1;
|
|
|
|
if (fBackslashCount mod 2 = 1) then inc(Run)
|
|
end;
|
|
inc(Run);
|
|
end;// '\':
|
|
|
|
'"':
|
|
if (fLine[Run + 1] = '"') and (fLine[Run + 2] = '"') then begin
|
|
fRange := rsUnKnown;
|
|
inc(Run, 3);
|
|
EXIT;
|
|
end else
|
|
inc(Run);
|
|
#10:EXIT;
|
|
#13:EXIT;
|
|
else
|
|
inc(Run);
|
|
end;
|
|
end;
|
|
end
|
|
else //if short string
|
|
repeat
|
|
case FLine[Run] of
|
|
#0, #10, #13 : begin
|
|
if FLine[Run-1] = '\' then begin
|
|
fStringStarter := '"';
|
|
fRange := rsMultilineString3;
|
|
end;
|
|
BREAK;
|
|
end;
|
|
{The same backslash stuff above...}
|
|
'\':begin
|
|
if FLine[Run + 1] = '"' then
|
|
begin
|
|
fBackslashCount := 1;
|
|
|
|
while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
|
|
fBackslashCount := fBackslashCount + 1;
|
|
|
|
if (fBackslashCount mod 2 = 1) then inc(Run)
|
|
end;
|
|
inc(Run);
|
|
end;// '\':
|
|
|
|
else inc(Run);
|
|
end; //case
|
|
until (FLine[Run] = '"');
|
|
if FLine[Run] <> #0 then inc(Run);
|
|
end;
|
|
|
|
procedure TSynPythonSyn.PreStringProc;
|
|
var
|
|
temp: Char;
|
|
|
|
begin
|
|
// Handle python raw strings
|
|
// r""
|
|
temp := FLine[Run + 1];
|
|
if temp = '''' then begin
|
|
Inc (Run);
|
|
StringProc;
|
|
end else if temp = '"' then begin
|
|
Inc (Run);
|
|
String2Proc;
|
|
end else begin
|
|
// If not followed by quote char, must be ident
|
|
IdentProc;
|
|
end; // if
|
|
end;
|
|
|
|
procedure TSynPythonSyn.UnicodeStringProc;
|
|
begin
|
|
// Handle python raw and unicode strings
|
|
// Valid syntax: u"", or ur""
|
|
if (FLine[Run + 1] in ['r', 'R']) and (FLine[Run + 2] in ['''', '"']) then
|
|
// for ur, Remove the "u" and...
|
|
Inc (Run);
|
|
// delegate to raw strings
|
|
PreStringProc;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.StringProc;
|
|
var fBackslashCount:integer;
|
|
begin
|
|
fTokenID := tkString;
|
|
if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then begin
|
|
fTokenID := tkTripleQuotedString;
|
|
inc(Run, 3);
|
|
|
|
fRange:=rsMultilineString;
|
|
while fLine[Run] <> #0 do begin
|
|
case fLine[Run] of
|
|
|
|
'\': begin
|
|
{ If we're looking at a backslash, and the following character is an
|
|
end quote, and it's preceeded by an odd number of backslashes, then
|
|
it shouldn't mark the end of the string. If it's preceeded by an
|
|
even number, then it should. !!!THIS RULE DOESNT APPLY IN RAW STRINGS}
|
|
if FLine[Run + 1] = #39 then
|
|
begin
|
|
fBackslashCount := 1;
|
|
|
|
while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
|
|
fBackslashCount := fBackslashCount + 1;
|
|
|
|
if (fBackslashCount mod 2 = 1) then inc(Run)
|
|
end;
|
|
inc(Run);
|
|
end;// '\':
|
|
|
|
#39:
|
|
if (fLine[Run + 1] = #39) and (fLine[Run + 2] = #39) then begin
|
|
fRange := rsUnKnown;
|
|
inc(Run, 3);
|
|
EXIT;
|
|
end else
|
|
inc(Run);
|
|
#10: EXIT;
|
|
#13: EXIT;
|
|
else
|
|
inc(Run);
|
|
end;
|
|
end;
|
|
end
|
|
else //if short string
|
|
repeat
|
|
case FLine[Run] of
|
|
#0, #10, #13 : begin
|
|
if FLine[Run-1] = '\' then begin
|
|
fStringStarter := #39;
|
|
fRange := rsMultilineString3;
|
|
end;
|
|
BREAK;
|
|
end;
|
|
|
|
{The same backslash stuff above...}
|
|
'\':begin
|
|
if FLine[Run + 1] = #39 then
|
|
begin
|
|
fBackslashCount := 1;
|
|
|
|
while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
|
|
fBackslashCount := fBackslashCount + 1;
|
|
|
|
if (fBackslashCount mod 2 = 1) then inc(Run)
|
|
end;
|
|
inc(Run);
|
|
end;// '\':
|
|
|
|
else inc(Run);
|
|
end; //case
|
|
until (FLine[Run] = #39);
|
|
if FLine[Run] <> #0 then inc(Run);
|
|
end;
|
|
|
|
procedure TSynPythonSyn.StringEndProc(EndChar:char);
|
|
var fBackslashCount:integer;
|
|
begin
|
|
if fRange = rsMultilineString3 then
|
|
fTokenID := tkString
|
|
else
|
|
fTokenID := tkTripleQuotedString;
|
|
|
|
case FLine[Run] of
|
|
#0:
|
|
begin
|
|
NullProc;
|
|
EXIT;
|
|
end;
|
|
#10:
|
|
begin
|
|
LFProc;
|
|
EXIT;
|
|
end;
|
|
#13:
|
|
begin
|
|
CRProc;
|
|
EXIT;
|
|
end;
|
|
end;
|
|
|
|
if fRange = rsMultilineString3 then begin
|
|
repeat
|
|
if FLine[Run]=fStringStarter then begin
|
|
inc(Run);
|
|
fRange:=rsUnknown;
|
|
EXIT;
|
|
end else if FLine[Run]='\' then {The same backslash stuff above...}
|
|
begin
|
|
if FLine[Run + 1] = fStringStarter then
|
|
begin
|
|
fBackslashCount := 1;
|
|
|
|
while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
|
|
fBackslashCount := fBackslashCount + 1;
|
|
|
|
if (fBackslashCount mod 2 = 1) then inc(Run);
|
|
end;
|
|
end;// if FLine[Run]...
|
|
|
|
inc(Run);
|
|
until (FLine[Run] in [#0, #10, #13]);
|
|
if FLine[Run-1]<>'\' then begin
|
|
fRange:=rsUnknown;
|
|
EXIT;
|
|
end;
|
|
end else
|
|
repeat
|
|
if FLine[Run] = '\' then
|
|
begin
|
|
if FLine[Run + 1] = EndChar then
|
|
begin
|
|
fBackslashCount := 1;
|
|
|
|
while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
|
|
fBackslashCount := fBackslashCount + 1;
|
|
|
|
if (fBackslashCount mod 2 = 1) then inc(Run,2);
|
|
end;
|
|
end;// if FLine[Run]...
|
|
if (FLine[Run]=EndChar) and (FLine[Run+1]=EndChar) and (FLine[Run+2]=EndChar) then begin
|
|
inc(Run,3);
|
|
fRange:=rsUnknown;
|
|
EXIT;
|
|
end;
|
|
inc(Run);
|
|
until (FLine[Run] in [#0, #10, #13]);
|
|
end;
|
|
|
|
procedure TSynPythonSyn.UnknownProc;
|
|
begin
|
|
inc(Run);
|
|
while (fLine[Run] in [#128..#191]) OR // continued utf8 subcode
|
|
((fLine[Run]<>#0) and (fProcTable[fLine[Run]] = @UnknownProc)) do inc(Run);
|
|
fTokenID := tkUnknown;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.Next;
|
|
begin
|
|
fTokenPos := Run;
|
|
|
|
case fRange of
|
|
rsMultilineString:
|
|
StringEndProc(#39);
|
|
rsMultilineString2:
|
|
StringEndProc('"');
|
|
rsMultilineString3:
|
|
StringEndProc(fStringStarter);
|
|
else
|
|
fProcTable[fLine[Run]];
|
|
end;
|
|
end;
|
|
|
|
function TSynPythonSyn.GetDefaultAttribute(Index: integer): TSynHighlighterAttributes;
|
|
begin
|
|
case Index of
|
|
SYN_ATTR_COMMENT: Result := fCommentAttri;
|
|
SYN_ATTR_KEYWORD: Result := fKeyAttri;
|
|
SYN_ATTR_WHITESPACE: Result := fSpaceAttri;
|
|
SYN_ATTR_SYMBOL: Result := fSymbolAttri;
|
|
SYN_ATTR_NUMBER: Result := fNumberAttri;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
|
|
function TSynPythonSyn.GetEol: Boolean;
|
|
begin
|
|
Result := fTokenId = tkNull;
|
|
end;
|
|
|
|
function TSynPythonSyn.GetRange: Pointer;
|
|
begin
|
|
Result := Pointer(PtrInt(fRange));
|
|
end;
|
|
|
|
function TSynPythonSyn.GetToken: string;
|
|
var
|
|
Len: LongInt;
|
|
begin
|
|
Result := '';
|
|
Len := Run - fTokenPos;
|
|
SetString(Result, (FLine + fTokenPos), Len);
|
|
end;
|
|
|
|
function TSynPythonSyn.GetTokenID: TtkTokenKind;
|
|
begin
|
|
Result := fTokenId;
|
|
end;
|
|
|
|
function TSynPythonSyn.GetTokenAttribute: TSynHighlighterAttributes;
|
|
begin
|
|
case fTokenID of
|
|
tkComment: Result := fCommentAttri;
|
|
tkIdentifier: Result := fIdentifierAttri;
|
|
tkKey: Result := fKeyAttri;
|
|
tkNonKeyword: Result := fNonKeyAttri;
|
|
tkSystemDefined: Result := fSystemAttri;
|
|
tkNumber: Result := fNumberAttri;
|
|
tkHex: Result := fHexAttri;
|
|
tkOct: Result := fOctalAttri;
|
|
tkFloat: Result := fFloatAttri;
|
|
tkSpace: Result := fSpaceAttri;
|
|
tkString: Result := fStringAttri;
|
|
tkTripleQuotedString: Result := fDocStringAttri;
|
|
tkSymbol: Result := fSymbolAttri;
|
|
tkUnknown: Result := fErrorAttri;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
end;
|
|
|
|
function TSynPythonSyn.GetTokenKind: integer;
|
|
begin
|
|
Result := Ord(fTokenId);
|
|
end;
|
|
|
|
function TSynPythonSyn.GetTokenPos: Integer;
|
|
begin
|
|
Result := fTokenPos;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.ResetRange;
|
|
begin
|
|
fRange := rsUnknown;
|
|
end;
|
|
|
|
procedure TSynPythonSyn.SetRange(Value: Pointer);
|
|
begin
|
|
fRange := TRangeState(PtrUInt(Value));
|
|
end;
|
|
|
|
function TSynPythonSyn.GetIdentChars: TSynIdentChars;
|
|
begin
|
|
Result := TSynValidStringChars;
|
|
end;
|
|
|
|
class function TSynPythonSyn.GetLanguageName: string;
|
|
begin
|
|
Result := SYNS_LangPython;
|
|
end;
|
|
|
|
function TSynPythonSyn.GetSampleSource: string;
|
|
begin
|
|
Result :=
|
|
'#!/usr/local/bin/python'#13#10 +
|
|
'import string, sys'#13#10 +
|
|
'""" If no arguments were given, print a helpful message """'#13#10 +
|
|
'if len(sys.argv)==1:'#13#10 +
|
|
' print ''Usage: celsius temp1 temp2 ...'''#13#10 +
|
|
' sys.exit(0)';
|
|
end;
|
|
|
|
initialization
|
|
RegisterPlaceableHighlighter(TSynPythonSyn);
|
|
|
|
finalization
|
|
GlobalKeywords.Free;
|
|
end.
|
|
|