1 {-------------------------------------------------------------------------------
2 The contents of this file are subject to the Mozilla Public License
3 Version 1.1 (the "License"); you may not use this file except in compliance
4 with the License. You may obtain a copy of the License at
5 http://www.mozilla.org/MPL/
6
7 Software distributed under the License is distributed on an "AS IS" basis,
8 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9 the specific language governing rights and limitations under the License.
10
11 The Original Code is: SynHighlighterPython.pas, released 2000-06-23.
12 The Original Code is based on the odPySyn.pas file from the
13 mwEdit component suite by Martin Waldenburg and other developers, the Initial
14 Author of this file is Olivier Deckmyn.
15 Portions created by M.Utku Karatas and Dennis Chuah.
16 All Rights Reserved.
17
18 Contributors to the SynEdit and mwEdit projects are listed in the
19 Contributors.txt file.
20
21 Alternatively, the contents of this file may be used under the terms of the
22 GNU General Public License Version 2 or later (the "GPL"), in which case
23 the provisions of the GPL are applicable instead of those above.
24 If you wish to allow use of your version of this file only under the terms
25 of the GPL and not to allow others to use your version of this file
26 under the MPL, indicate your decision by deleting the provisions above and
27 replace them with the notice and other provisions required by the GPL.
28 If you do not delete the provisions above, a recipient may use your version
29 of this file under either the MPL or the GPL.
30
31 $Id: synhighlighterpython.pas 52753 2016-07-28 07:56:24Z mattias $
32
33 You may retrieve the latest version of this file at the SynEdit home page,
34 located at http://SynEdit.SourceForge.net
35
36 Known Issues:
37 -------------------------------------------------------------------------------}
38 {
39 @abstract(A Python language highlighter for SynEdit)
40 @author(Olivier Deckmyn, converted to SynEdit by David Muir <dhmn@dmsoftware.co.uk>)
41 @created(unknown, converted to SynEdit on 2000-06-23)
42 @lastmod(2003-02-13)
43 The SynHighlighterPython implements a highlighter for Python for the SynEdit projects.
44 }
45 unit SynHighlighterPython;
46
47 {$I SynEdit.inc}
48
49 interface
50
51 uses
52 IniFiles, //THashedStringList
53 LCLIntf, LCLType,
54 SynEditHighlighter, SynEditTypes,
55 Graphics, SysUtils, Classes;
56
57 const
58 ALPHA_CHARS = ['_', 'a'..'z', 'A'..'Z'];
59 IDENTIFIER_CHARS = ['0'..'9'] + ALPHA_CHARS;
60
61 type
62 TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
63 tkString, tkSymbol, tkNonKeyword, tkTripleQuotedString,
64 tkSystemDefined, tkHex, tkOct, tkFloat, tkUnknown);
65
66 TRangeState = (rsANil, rsComment, rsUnKnown, rsMultilineString, rsMultilineString2,
67 rsMultilineString3 //this is to indicate if a string is made multiline by backslash char at line end (as in C++ highlighter)
68 );
69
70 TProcTableProc = procedure of object;
71
72 type
73 TSynPythonSyn = class(TSynCustomHighLighter)
74 private
75 fStringStarter: char; // used only for rsMultilineString3 stuff
76 fRange: TRangeState;
77 fLine: PChar;
78 fLineNumber: Integer;
79 fProcTable: array[#0..#255] of TProcTableProc;
80 fToIdent: PChar;
81 fTokenPos: Integer;
82 FTokenID: TtkTokenKind;
83 FKeywords: TStringList;
84
85 fStringAttri: TSynHighlighterAttributes;
86 fDocStringAttri: TSynHighlighterAttributes;
87 fNumberAttri: TSynHighlighterAttributes;
88 fHexAttri: TSynHighlighterAttributes;
89 fOctalAttri: TSynHighlighterAttributes;
90 fFloatAttri: TSynHighlighterAttributes;
91 fKeyAttri: TSynHighlighterAttributes;
92 fNonKeyAttri: TSynHighlighterAttributes;
93 fSystemAttri: TSynHighlighterAttributes;
94 fSymbolAttri: TSynHighlighterAttributes;
95 fCommentAttri: TSynHighlighterAttributes;
96 fIdentifierAttri: TSynHighlighterAttributes;
97 fSpaceAttri: TSynHighlighterAttributes;
98 fErrorAttri: TSynHighlighterAttributes;
99
100 procedure SymbolProc;
101 procedure CRProc;
102 procedure CommentProc;
103 procedure GreaterProc;
104 procedure IdentProc;
105 procedure LFProc;
106 procedure LowerProc;
107 procedure NullProc;
108 procedure NumberProc;
109 procedure SpaceProc;
110 procedure PreStringProc;
111 procedure UnicodeStringProc;
112 procedure StringProc;
113 procedure String2Proc;
114 procedure StringEndProc(EndChar:char);
115 procedure UnknownProc;
116 procedure MakeMethodTables;
117
118 protected
119 Run: LongInt;
120 fStringLen: Integer;
121
GetIdentCharsnull122 function GetIdentChars: TSynIdentChars; override;
GetSampleSourcenull123 function GetSampleSource: string; override;
IdentKindnull124 function IdentKind(MayBe: PChar): TtkTokenKind; virtual;
125 property Keywords: TStringlist read FKeywords;
126 property TokenID: TtkTokenKind read FTokenID;
127
128 public
GetLanguageNamenull129 class function GetLanguageName: string; override;
130 public
131 constructor Create(AOwner: TComponent); override;
132 destructor Destroy; override;
GetDefaultAttributenull133 function GetDefaultAttribute(Index: integer): TSynHighlighterAttributes;
134 override;
GetEolnull135 function GetEol: Boolean; override;
GetRangenull136 function GetRange: Pointer; override;
GetTokenIDnull137 function GetTokenID: TtkTokenKind;
138 procedure SetLine(const NewValue: string;
139 LineNumber: Integer); override;
GetKeywordIdentifiersnull140 function GetKeywordIdentifiers: TStringList; virtual;
GetTokennull141 function GetToken: string; override;
GetTokenAttributenull142 function GetTokenAttribute: TSynHighlighterAttributes; override;
GetTokenKindnull143 function GetTokenKind: integer; override;
GetTokenPosnull144 function GetTokenPos: Integer; override;
145 procedure Next; override;
146 property IdentChars;
147 procedure SetRange(Value: Pointer); override;
148 procedure ResetRange; override;
149 procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
150 published
151 property CommentAttri: TSynHighlighterAttributes read fCommentAttri
152 write fCommentAttri;
153 property IdentifierAttri: TSynHighlighterAttributes read fIdentifierAttri
154 write fIdentifierAttri;
155 property KeyAttri: TSynHighlighterAttributes read fKeyAttri write fKeyAttri;
156 property NonKeyAttri: TSynHighlighterAttributes read fNonKeyAttri
157 write fNonKeyAttri;
158 property SystemAttri: TSynHighlighterAttributes read fSystemAttri
159 write fSystemAttri;
160 property NumberAttri: TSynHighlighterAttributes read fNumberAttri
161 write fNumberAttri;
162 property HexAttri: TSynHighlighterAttributes read fHexAttri
163 write fHexAttri;
164 property OctalAttri: TSynHighlighterAttributes read fOctalAttri
165 write fOctalAttri;
166 property FloatAttri: TSynHighlighterAttributes read fFloatAttri
167 write fFloatAttri;
168 property SpaceAttri: TSynHighlighterAttributes read fSpaceAttri
169 write fSpaceAttri;
170 property StringAttri: TSynHighlighterAttributes read fStringAttri
171 write fStringAttri;
172 property DocStringAttri: TSynHighlighterAttributes read fDocStringAttri
173 write fDocStringAttri;
174 property SymbolAttri: TSynHighlighterAttributes read fSymbolAttri
175 write fSymbolAttri;
176 property ErrorAttri: TSynHighlighterAttributes read fErrorAttri
177 write fErrorAttri;
178 end;
179
180 implementation
181
182 uses
183 SynEditStrConst;
184
185 var
186 GlobalKeywords: TStringList;
187
TSynPythonSyn.GetKeywordIdentifiersnull188 function TSynPythonSyn.GetKeywordIdentifiers: TStringList;
189 const
190 // No need to localise keywords!
191
192 // List of keywords
193 KEYWORDCOUNT = 29;
194 KEYWORDSIdents: array [1..KEYWORDCOUNT] of string =
195 (
196 'and',
197 'assert',
198 'break',
199 'class',
200 'continue',
201 'def',
202 'del',
203 'elif',
204 'else',
205 'except',
206 'exec',
207 'finally',
208 'for',
209 'from',
210 'global',
211 'if',
212 'import',
213 'in',
214 'is',
215 'lambda',
216 'not',
217 'or',
218 'pass',
219 'print',
220 'raise',
221 'return',
222 'try',
223 'while',
224 'yield'
225 );
226
227 // List of non-keyword identifiers
228 NONKEYWORDCOUNT = 66;
229 NONKEYWORDS: array [1..NONKEYWORDCOUNT] of string =
230 (
231 '__future__',
232 '__import__',
233 'abs',
234 'apply',
235 'as',
236 'buffer',
237 'callable',
238 'chr',
239 'cmp',
240 'coerce',
241 'compile',
242 'complex',
243 'delattr',
244 'dict',
245 'dir',
246 'divmod',
247 'eval',
248 'execfile',
249 'False',
250 'file',
251 'filter',
252 'float',
253 'getattr',
254 'globals',
255 'hasattr',
256 'hash',
257 'help',
258 'hex',
259 'id',
260 'input',
261 'int',
262 'intern',
263 'isinstance',
264 'issubclass',
265 'iter',
266 'len',
267 'list',
268 'locals',
269 'long',
270 'None',
271 'NotImplemented',
272 'map',
273 'max',
274 'min',
275 'oct',
276 'open',
277 'ord',
278 'pow',
279 'range',
280 'raw_input',
281 'reduce',
282 'reload',
283 'repr',
284 'round',
285 'self',
286 'setattr',
287 'slice',
288 'str',
289 'True',
290 'tuple',
291 'type',
292 'unichr',
293 'unicode',
294 'vars',
295 'xrange',
296 'zip'
297 );
298 var
299 f: Integer;
300 begin
301 if not Assigned (GlobalKeywords) then begin
302 // Create the string list of keywords - only once
303 GlobalKeywords := TStringList.Create;
304
305 for f := 1 to KEYWORDCOUNT do
306 GlobalKeywords.AddObject (KEYWORDSIdents[f],
307 TObject(Ord(tkKey)));
308 for f := 1 to NONKEYWORDCOUNT do
309 GlobalKeywords.AddObject (NONKEYWORDS[f],
310 TObject(Ord(tkNonKeyword)));
311 end; // if
312 Result := GlobalKeywords;
313 end;
314
TSynPythonSyn.IdentKindnull315 function TSynPythonSyn.IdentKind(MayBe: PChar): TtkTokenKind;
316 var
317 index: Integer;
318 temp: PChar;
319 s: string;
320
321 begin
322 // Extract the identifier out - it is assumed to terminate in a
323 // non-alphanumeric character
324 fToIdent := MayBe;
325 temp := MayBe;
326 while temp^ in IDENTIFIER_CHARS do
327 Inc (temp);
328 fStringLen := temp - fToIdent;
329
330 // Check to see if it is a keyword
331 SetString (s, fToIdent, fStringLen);
332 index := FKeywords.IndexOf (s);
333
334 if index <> -1 then
335 Result := TtkTokenKind (PtrInt(FKeywords.Objects[index]))
336
337 // Check if it is a system identifier (__*__)
338 else if (fStringLen >= 5) and
339 (MayBe[0] = '_') and (MayBe[1] = '_') and (MayBe[2] <> '_') and
340 (MayBe[fStringLen-1] = '_') and (MayBe[fStringLen-2] = '_') and
341 (MayBe[fStringLen-3] <> '_') then
342 Result := tkSystemDefined
343
344 // Else, hey, it is an ordinary run-of-the-mill identifier!
345 else
346 Result := tkIdentifier;
347 end;
348
349 procedure TSynPythonSyn.MakeMethodTables;
350 var
351 I: Char;
352 begin
353 for I := #0 to #255 do
354 case I of
355 '&', '}', '{', ':', ',', ']', '[', '*', '`',
356 '^', ')', '(', ';', '/', '=', '-', '+', '!', '\',
357 '%', '|', '~' :
358 fProcTable[I] := @SymbolProc;
359 #13: fProcTable[I] := @CRProc;
360 '#': fProcTable[I] := @CommentProc;
361 '>': fProcTable[I] := @GreaterProc;
362 'A'..'Q', 'S', 'T', 'V'..'Z', 'a'..'q', 's', 't', 'v'..'z', '_': fProcTable[I] := @IdentProc;
363 #10: fProcTable[I] := @LFProc;
364 '<': fProcTable[I] := @LowerProc;
365 #0: fProcTable[I] := @NullProc;
366 '.', '0'..'9': fProcTable[I] := @NumberProc;
367 #1..#9, #11, #12, #14..#32:
368 fProcTable[I] := @SpaceProc;
369 'r', 'R': fProcTable[I] := @PreStringProc;
370 'u', 'U': fProcTable[I] := @UnicodeStringProc;
371 '''': fProcTable[I] := @StringProc;
372 '"': fProcTable[I] := @String2Proc;
373 else
374 fProcTable[I] := @UnknownProc;
375 end;
376 end;
377
378 constructor TSynPythonSyn.Create(AOwner: TComponent);
379 begin
380 inherited Create(AOwner);
381
382 FKeywords := THashedStringList.Create;
383 FKeywords.CaseSensitive := True;
384 FKeywords.Duplicates := dupError;
385 FKeywords.Assign (GetKeywordIdentifiers);
386
387 fRange := rsUnknown;
388 fCommentAttri := TSynHighlighterAttributes.Create(@SYNS_AttrComment, SYNS_XML_AttrComment);
389 fCommentAttri.Foreground := clGray;
390 fCommentAttri.Style := [fsItalic];
391 AddAttribute(fCommentAttri);
392 fIdentifierAttri := TSynHighlighterAttributes.Create(@SYNS_AttrIdentifier, SYNS_XML_AttrIdentifier);
393 AddAttribute(fIdentifierAttri);
394 fKeyAttri := TSynHighlighterAttributes.Create(@SYNS_AttrReservedWord, SYNS_XML_AttrReservedWord);
395 fKeyAttri.Style := [fsBold];
396 AddAttribute(fKeyAttri);
397 fNonKeyAttri := TSynHighlighterAttributes.Create(@SYNS_AttrNonReservedKeyword, SYNS_XML_AttrNonReservedKeyword);
398 fNonKeyAttri.Foreground := clNavy;
399 fNonKeyAttri.Style := [fsBold];
400 AddAttribute (fNonKeyAttri);
401 fSystemAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSystem, SYNS_XML_AttrSystem);
402 fSystemAttri.Style := [fsBold];
403 AddAttribute (fSystemAttri);
404 fNumberAttri := TSynHighlighterAttributes.Create(@SYNS_AttrNumber, SYNS_XML_AttrNumber);
405 fNumberAttri.Foreground := clBlue;
406 AddAttribute(fNumberAttri);
407 fHexAttri := TSynHighlighterAttributes.Create(@SYNS_AttrHexadecimal, SYNS_XML_AttrHexadecimal);
408 fHexAttri.Foreground := clBlue;
409 AddAttribute(fHexAttri);
410 fOctalAttri := TSynHighlighterAttributes.Create(@SYNS_AttrOctal, SYNS_XML_AttrOctal);
411 fOctalAttri.Foreground := clBlue;
412 AddAttribute(fOctalAttri);
413 fFloatAttri := TSynHighlighterAttributes.Create(@SYNS_AttrFloat, SYNS_XML_AttrFloat);
414 fFloatAttri.Foreground := clBlue;
415 AddAttribute(fFloatAttri);
416 fSpaceAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSpace, SYNS_XML_AttrSpace);
417 AddAttribute(fSpaceAttri);
418 fStringAttri := TSynHighlighterAttributes.Create(@SYNS_AttrString, SYNS_XML_AttrString);
419 fStringAttri.Foreground := clBlue;
420 AddAttribute(fStringAttri);
421 fDocStringAttri := TSynHighlighterAttributes.Create(@SYNS_AttrDocumentation, SYNS_XML_AttrDocumentation);
422 fDocStringAttri.Foreground := clTeal;
423 AddAttribute(fDocStringAttri);
424 fSymbolAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSymbol, SYNS_XML_AttrSymbol);
425 AddAttribute(fSymbolAttri);
426 fErrorAttri := TSynHighlighterAttributes.Create(@SYNS_AttrSyntaxError, SYNS_XML_AttrSyntaxError);
427 fErrorAttri.Foreground := clRed;
428 AddAttribute(fErrorAttri);
429 SetAttributesOnChange(@DefHighlightChange);
430 MakeMethodTables;
431 fDefaultFilter := SYNS_FilterPython;
432 end; { Create }
433
434 destructor TSynPythonSyn.Destroy;
435 begin
436 FKeywords.Free;
437
438 inherited;
439 end;
440
441 procedure TSynPythonSyn.SetLine(const NewValue: string;
442 LineNumber: Integer);
443 begin
444 inherited;
445 fLine := PChar(NewValue);
446 Run := 0;
447 fLineNumber := LineNumber;
448 Next;
449 end; { SetLine }
450
451 procedure TSynPythonSyn.GetTokenEx(out TokenStart: PChar;
452 out TokenLength: integer);
453 begin
454 TokenLength:=Run-fTokenPos;
455 TokenStart:=FLine + fTokenPos;
456 end;
457
458 procedure TSynPythonSyn.SymbolProc;
459 begin
460 inc(Run);
461 fTokenID := tkSymbol;
462 end;
463
464 procedure TSynPythonSyn.CRProc;
465 begin
466 fTokenID := tkSpace;
467 case FLine[Run + 1] of
468 #10: inc(Run, 2);
469 else
470 inc(Run);
471 end;
472 end;
473
474 procedure TSynPythonSyn.CommentProc;
475 begin
476 fTokenID := tkComment;
477 inc(Run);
478 while not (FLine[Run] in [#13, #10, #0]) do
479 inc(Run);
480 end;
481
482 procedure TSynPythonSyn.GreaterProc;
483 begin
484 case FLine[Run + 1] of
485 '=': begin
486 inc(Run, 2);
487 fTokenID := tkSymbol;
488 end;
489 else begin
490 inc(Run);
491 fTokenID := tkSymbol;
492 end;
493 end;
494 end;
495
496 procedure TSynPythonSyn.IdentProc;
497 begin
498 fTokenID := IdentKind((fLine + Run));
499 inc(Run, fStringLen);
500 end;
501
502 procedure TSynPythonSyn.LFProc;
503 begin
504 fTokenID := tkSpace;
505 inc(Run);
506 end;
507
508 procedure TSynPythonSyn.LowerProc;
509 begin
510 case FLine[Run + 1] of
511 '=': begin
512 inc(Run, 2);
513 fTokenID := tkSymbol;
514 end;
515 '>': begin
516 inc(Run, 2);
517 fTokenID := tkSymbol;
518 end
519 else begin
520 inc(Run);
521 fTokenID := tkSymbol;
522 end;
523 end;
524 end;
525
526 procedure TSynPythonSyn.NullProc;
527 begin
528 fTokenID := tkNull;
529 end;
530
531 procedure TSynPythonSyn.NumberProc;
532 const
533 INTCHARS = ['0' .. '9'];
534 HEXCHARS = ['a' .. 'f', 'A' .. 'F'] + INTCHARS;
535 OCTCHARS = ['0' .. '7'];
536 HEXINDICATOR = ['x', 'X'];
537 LONGINDICATOR = ['l', 'L'];
538 IMAGINARYINDICATOR = ['j', 'J'];
539 EXPONENTINDICATOR = ['e', 'E'];
540 EXPONENTSIGN = ['+', '-'];
541 DOT = '.';
542 ZERO = '0';
543
544 type
545 TNumberState =
546 (
547 nsStart,
548 nsDotFound,
549 nsFloatNeeded,
550 nsHex,
551 nsOct,
552 nsExpFound
553 );
554
555 var
556 temp: Char;
557 State: TNumberState;
558
CheckSpecialCasesnull559 function CheckSpecialCases: Boolean;
560 begin
561 case temp of
562 // Look for dot (.)
563 DOT: begin
564 // .45
565 if FLine[Run] in INTCHARS then begin
566 Inc (Run);
567 fTokenID := tkFloat;
568 State := nsDotFound;
569
570 // Non-number dot
571 end else begin
572 // Ellipsis
573 if (FLine[Run] = DOT) and (FLine[Run+1] = DOT) then
574 Inc (Run, 2);
575 fTokenID := tkSymbol;
576 Result := False;
577 Exit;
578 end; // if
579 end; // DOT
580
581 // Look for zero (0)
582 ZERO: begin
583 temp := FLine[Run];
584 // 0x123ABC
585 if temp in HEXINDICATOR then begin
586 Inc (Run);
587 fTokenID := tkHex;
588 State := nsHex;
589 // 0.45
590 end else if temp = DOT then begin
591 Inc (Run);
592 State := nsDotFound;
593 fTokenID := tkFloat;
594 end else if temp in INTCHARS then begin
595 Inc (Run);
596 // 0123 or 0123.45
597 if temp in OCTCHARS then begin
598 fTokenID := tkOct;
599 State := nsOct;
600 // 0899.45
601 end else begin
602 fTokenID := tkFloat;
603 State := nsFloatNeeded;
604 end; // if
605 end; // if
606 end; // ZERO
607 end; // case
608
609 Result := True;
610 end; // CheckSpecialCases
611
HandleBadNumbernull612 function HandleBadNumber: Boolean;
613 begin
614 Result := False;
615 fTokenID := tkUnknown;
616 // Ignore all tokens till end of "number"
617 while FLine[Run] in (IDENTIFIER_CHARS + ['.']) do
618 Inc (Run);
619 end; // HandleBadNumber
620
HandleExponentnull621 function HandleExponent: Boolean;
622 begin
623 State := nsExpFound;
624 fTokenID := tkFloat;
625 // Skip e[+/-]
626 if FLine[Run+1] in EXPONENTSIGN then
627 Inc (Run);
628 // Invalid token : 1.0e
629 if not (FLine[Run+1] in INTCHARS) then begin
630 Inc (Run);
631 Result := HandleBadNumber;
632 Exit;
633 end; // if
634
635 Result := True;
636 end; // HandleExponent
637
HandleDotnull638 function HandleDot: Boolean;
639 begin
640 // Check for ellipsis
641 Result := (FLine[Run+1] <> DOT) or (FLine[Run+2] <> DOT);
642 if Result then begin
643 State := nsDotFound;
644 fTokenID := tkFloat;
645 end; // if
646 end; // HandleDot
647
CheckStartnull648 function CheckStart: Boolean;
649 begin
650 // 1234
651 if temp in INTCHARS then begin
652 Result := True;
653 //123e4
654 end else if temp in EXPONENTINDICATOR then begin
655 Result := HandleExponent;
656 // 123.45j
657 end else if temp in IMAGINARYINDICATOR then begin
658 Inc (Run);
659 fTokenID := tkFloat;
660 Result := False;
661 // 123.45
662 end else if temp = DOT then begin
663 Result := HandleDot;
664 // Error!
665 end else if temp in IDENTIFIER_CHARS then begin
666 Result := HandleBadNumber;
667 // End of number
668 end else begin
669 Result := False;
670 end; // if
671 end; // CheckStart
672
CheckDotFoundnull673 function CheckDotFound: Boolean;
674 begin
675 // 1.0e4
676 if temp in EXPONENTINDICATOR then begin
677 Result := HandleExponent;
678 // 123.45
679 end else if temp in INTCHARS then begin
680 Result := True;
681 // 123.45j
682 end else if temp in IMAGINARYINDICATOR then begin
683 Inc (Run);
684 Result := False;
685 // 123.45.45: Error!
686 end else if temp = DOT then begin
687 Result := False;
688 if HandleDot then
689 HandleBadNumber;
690 // Error!
691 end else if temp in IDENTIFIER_CHARS then begin
692 Result := HandleBadNumber;
693 // End of number
694 end else begin
695 Result := False;
696 end; // if
697 end; // CheckDotFound
698
CheckFloatNeedednull699 function CheckFloatNeeded: Boolean;
700 begin
701 // 091.0e4
702 if temp in EXPONENTINDICATOR then begin
703 Result := HandleExponent;
704 // 0912345
705 end else if temp in INTCHARS then begin
706 Result := True;
707 // 09123.45
708 end else if temp = DOT then begin
709 Result := HandleDot or HandleBadNumber; // Bad octal
710 // 09123.45j
711 end else if temp in IMAGINARYINDICATOR then begin
712 Inc (Run);
713 Result := False;
714 // End of number (error: Bad oct number) 0912345
715 end else begin
716 Result := HandleBadNumber;
717 end;
718 end; // CheckFloatNeeded
719
CheckHexnull720 function CheckHex: Boolean;
721 begin
722 // 0x123ABC
723 if temp in HEXCHARS then begin
724 Result := True;
725 // 0x123ABCL
726 end else if temp in LONGINDICATOR then begin
727 Inc (Run);
728 Result := False;
729 // 0x123.45: Error!
730 end else if temp = DOT then begin
731 Result := False;
732 if HandleDot then
733 HandleBadNumber;
734 // Error!
735 end else if temp in IDENTIFIER_CHARS then begin
736 Result := HandleBadNumber;
737 // End of number
738 end else begin
739 Result := False;
740 end; // if
741 end; // CheckHex
742
CheckOctnull743 function CheckOct: Boolean;
744 begin
745 // 012345
746 if temp in INTCHARS then begin
747 if not (temp in OCTCHARS) then begin
748 State := nsFloatNeeded;
749 fTokenID := tkFloat;
750 end; // if
751 Result := True;
752 // 012345L
753 end else if temp in LONGINDICATOR then begin
754 Inc (Run);
755 Result := False;
756 // 0123e4
757 end else if temp in EXPONENTINDICATOR then begin
758 Result := HandleExponent;
759 // 0123j
760 end else if temp in IMAGINARYINDICATOR then begin
761 Inc (Run);
762 fTokenID := tkFloat;
763 Result := False;
764 // 0123.45
765 end else if temp = DOT then begin
766 Result := HandleDot;
767 // Error!
768 end else if temp in IDENTIFIER_CHARS then begin
769 Result := HandleBadNumber;
770 // End of number
771 end else begin
772 Result := False;
773 end; // if
774 end; // CheckOct
775
CheckExpFoundnull776 function CheckExpFound: Boolean;
777 begin
778 // 1e+123
779 if temp in INTCHARS then begin
780 Result := True;
781 // 1e+123j
782 end else if temp in IMAGINARYINDICATOR then begin
783 Inc (Run);
784 Result := False;
785 // 1e4.5: Error!
786 end else if temp = DOT then begin
787 Result := False;
788 if HandleDot then
789 HandleBadNumber;
790 // Error!
791 end else if temp in IDENTIFIER_CHARS then begin
792 Result := HandleBadNumber;
793 // End of number
794 end else begin
795 Result := False;
796 end; // if
797 end; // CheckExpFound
798
799 begin
800 State := nsStart;
801 fTokenID := tkNumber;
802
803 temp := FLine[Run];
804 Inc (Run);
805
806 // Special cases
807 if not CheckSpecialCases then
808 Exit;
809
810 // Use a state machine to parse numbers
811 while True do begin
812 temp := FLine[Run];
813
814 case State of
815 nsStart:
816 if not CheckStart then Exit;
817 nsDotFound:
818 if not CheckDotFound then Exit;
819 nsFloatNeeded:
820 if not CheckFloatNeeded then Exit;
821 nsHex:
822 if not CheckHex then Exit;
823 nsOct:
824 if not CheckOct then Exit;
825 nsExpFound:
826 if not CheckExpFound then Exit;
827 end; // case
828
829 Inc (Run);
830 end; // while
831
832 {
833 begin
834 while FLine[Run] in ['0'..'9', '.', 'e', 'E'] do begin
835 case FLine[Run] of
836 '.':
837 if FLine[Run + 1] = '.' then break;
838 end;
839 inc(Run);
840 end;
841 }
842 end;
843
844 procedure TSynPythonSyn.SpaceProc;
845 begin
846 inc(Run);
847 fTokenID := tkSpace;
848 while FLine[Run] in [#1..#9, #11, #12, #14..#32] do
849 inc(Run);
850 end;
851
852 procedure TSynPythonSyn.String2Proc;
853 var fBackslashCount:integer;
854 begin
855 fTokenID := tkString;
856 if (FLine[Run + 1] = '"') and (FLine[Run + 2] = '"') then begin
857 fTokenID := tkTripleQuotedString;
858 inc(Run, 3);
859
860 fRange:=rsMultilineString2;
861 while fLine[Run] <> #0 do begin
862 case fLine[Run] of
863
864 '\':begin
865 { If we're looking at a backslash, and the following character is an
866 end quote, and it's preceeded by an odd number of backslashes, then
867 it shouldn't mark the end of the string. If it's preceeded by an
868 even number, then it should. !!!THIS RULE DOESNT APPLY IN RAW STRINGS}
869 if FLine[Run + 1] = '"' then
870 begin
871 fBackslashCount := 1;
872
873 while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
874 fBackslashCount := fBackslashCount + 1;
875
876 if (fBackslashCount mod 2 = 1) then inc(Run)
877 end;
878 inc(Run);
879 end;// '\':
880
881 '"':
882 if (fLine[Run + 1] = '"') and (fLine[Run + 2] = '"') then begin
883 fRange := rsUnKnown;
884 inc(Run, 3);
885 EXIT;
886 end else
887 inc(Run);
888 #10:EXIT;
889 #13:EXIT;
890 else
891 inc(Run);
892 end;
893 end;
894 end
895 else //if short string
896 repeat
897 case FLine[Run] of
898 #0, #10, #13 : begin
899 if FLine[Run-1] = '\' then begin
900 fStringStarter := '"';
901 fRange := rsMultilineString3;
902 end;
903 BREAK;
904 end;
905 {The same backslash stuff above...}
906 '\':begin
907 if FLine[Run + 1] = '"' then
908 begin
909 fBackslashCount := 1;
910
911 while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
912 fBackslashCount := fBackslashCount + 1;
913
914 if (fBackslashCount mod 2 = 1) then inc(Run)
915 end;
916 inc(Run);
917 end;// '\':
918
919 else inc(Run);
920 end; //case
921 until (FLine[Run] = '"');
922 if FLine[Run] <> #0 then inc(Run);
923 end;
924
925 procedure TSynPythonSyn.PreStringProc;
926 var
927 temp: Char;
928
929 begin
930 // Handle python raw strings
931 // r""
932 temp := FLine[Run + 1];
933 if temp = '''' then begin
934 Inc (Run);
935 StringProc;
936 end else if temp = '"' then begin
937 Inc (Run);
938 String2Proc;
939 end else begin
940 // If not followed by quote char, must be ident
941 IdentProc;
942 end; // if
943 end;
944
945 procedure TSynPythonSyn.UnicodeStringProc;
946 begin
947 // Handle python raw and unicode strings
948 // Valid syntax: u"", or ur""
949 if (FLine[Run + 1] in ['r', 'R']) and (FLine[Run + 2] in ['''', '"']) then
950 // for ur, Remove the "u" and...
951 Inc (Run);
952 // delegate to raw strings
953 PreStringProc;
954 end;
955
956 procedure TSynPythonSyn.StringProc;
957 var fBackslashCount:integer;
958 begin
959 fTokenID := tkString;
960 if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then begin
961 fTokenID := tkTripleQuotedString;
962 inc(Run, 3);
963
964 fRange:=rsMultilineString;
965 while fLine[Run] <> #0 do begin
966 case fLine[Run] of
967
968 '\': begin
969 { If we're looking at a backslash, and the following character is an
970 end quote, and it's preceeded by an odd number of backslashes, then
971 it shouldn't mark the end of the string. If it's preceeded by an
972 even number, then it should. !!!THIS RULE DOESNT APPLY IN RAW STRINGS}
973 if FLine[Run + 1] = #39 then
974 begin
975 fBackslashCount := 1;
976
977 while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
978 fBackslashCount := fBackslashCount + 1;
979
980 if (fBackslashCount mod 2 = 1) then inc(Run)
981 end;
982 inc(Run);
983 end;// '\':
984
985 #39:
986 if (fLine[Run + 1] = #39) and (fLine[Run + 2] = #39) then begin
987 fRange := rsUnKnown;
988 inc(Run, 3);
989 EXIT;
990 end else
991 inc(Run);
992 #10: EXIT;
993 #13: EXIT;
994 else
995 inc(Run);
996 end;
997 end;
998 end
999 else //if short string
1000 repeat
1001 case FLine[Run] of
1002 #0, #10, #13 : begin
1003 if FLine[Run-1] = '\' then begin
1004 fStringStarter := #39;
1005 fRange := rsMultilineString3;
1006 end;
1007 BREAK;
1008 end;
1009
1010 {The same backslash stuff above...}
1011 '\':begin
1012 if FLine[Run + 1] = #39 then
1013 begin
1014 fBackslashCount := 1;
1015
1016 while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
1017 fBackslashCount := fBackslashCount + 1;
1018
1019 if (fBackslashCount mod 2 = 1) then inc(Run)
1020 end;
1021 inc(Run);
1022 end;// '\':
1023
1024 else inc(Run);
1025 end; //case
1026 until (FLine[Run] = #39);
1027 if FLine[Run] <> #0 then inc(Run);
1028 end;
1029
1030 procedure TSynPythonSyn.StringEndProc(EndChar:char);
1031 var fBackslashCount:integer;
1032 begin
1033 if fRange = rsMultilineString3 then
1034 fTokenID := tkString
1035 else
1036 fTokenID := tkTripleQuotedString;
1037
1038 case FLine[Run] of
1039 #0:
1040 begin
1041 NullProc;
1042 EXIT;
1043 end;
1044 #10:
1045 begin
1046 LFProc;
1047 EXIT;
1048 end;
1049 #13:
1050 begin
1051 CRProc;
1052 EXIT;
1053 end;
1054 end;
1055
1056 if fRange = rsMultilineString3 then begin
1057 repeat
1058 if FLine[Run]=fStringStarter then begin
1059 inc(Run);
1060 fRange:=rsUnknown;
1061 EXIT;
1062 end else if FLine[Run]='\' then ; {The same backslash stuff above...}
1063 begin
1064 if FLine[Run + 1] = fStringStarter then
1065 begin
1066 fBackslashCount := 1;
1067
1068 while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
1069 fBackslashCount := fBackslashCount + 1;
1070
1071 if (fBackslashCount mod 2 = 1) then inc(Run);
1072 end;
1073 end;// if FLine[Run]...
1074
1075 inc(Run);
1076 until (FLine[Run] in [#0, #10, #13]);
1077 if FLine[Run-1]<>'\' then begin
1078 fRange:=rsUnknown;
1079 EXIT;
1080 end;
1081 end else
1082 repeat
1083 if FLine[Run] = '\' then
1084 begin
1085 if FLine[Run + 1] = EndChar then
1086 begin
1087 fBackslashCount := 1;
1088
1089 while ((Run > fBackslashCount) and (FLine[Run - fBackslashCount] = '\')) do
1090 fBackslashCount := fBackslashCount + 1;
1091
1092 if (fBackslashCount mod 2 = 1) then inc(Run,2);
1093 end;
1094 end;// if FLine[Run]...
1095 if (FLine[Run]=EndChar) and (FLine[Run+1]=EndChar) and (FLine[Run+2]=EndChar) then begin
1096 inc(Run,3);
1097 fRange:=rsUnknown;
1098 EXIT;
1099 end;
1100 inc(Run);
1101 until (FLine[Run] in [#0, #10, #13]);
1102 end;
1103
1104 procedure TSynPythonSyn.UnknownProc;
1105 begin
1106 inc(Run);
1107 while (fLine[Run] in [#128..#191]) OR // continued utf8 subcode
1108 ((fLine[Run]<>#0) and (fProcTable[fLine[Run]] = @UnknownProc)) do inc(Run);
1109 fTokenID := tkUnknown;
1110 end;
1111
1112 procedure TSynPythonSyn.Next;
1113 begin
1114 fTokenPos := Run;
1115
1116 case fRange of
1117 rsMultilineString:
1118 StringEndProc(#39);
1119 rsMultilineString2:
1120 StringEndProc('"');
1121 rsMultilineString3:
1122 StringEndProc(fStringStarter);
1123 else
1124 fProcTable[fLine[Run]];
1125 end;
1126 end;
1127
TSynPythonSyn.GetDefaultAttributenull1128 function TSynPythonSyn.GetDefaultAttribute(Index: integer): TSynHighlighterAttributes;
1129 begin
1130 case Index of
1131 SYN_ATTR_COMMENT: Result := fCommentAttri;
1132 SYN_ATTR_KEYWORD: Result := fKeyAttri;
1133 SYN_ATTR_WHITESPACE: Result := fSpaceAttri;
1134 SYN_ATTR_SYMBOL: Result := fSymbolAttri;
1135 SYN_ATTR_NUMBER: Result := fNumberAttri;
1136 else
1137 Result := nil;
1138 end;
1139 end;
1140
GetEolnull1141 function TSynPythonSyn.GetEol: Boolean;
1142 begin
1143 Result := fTokenId = tkNull;
1144 end;
1145
TSynPythonSyn.GetRangenull1146 function TSynPythonSyn.GetRange: Pointer;
1147 begin
1148 Result := Pointer(PtrInt(fRange));
1149 end;
1150
TSynPythonSyn.GetTokennull1151 function TSynPythonSyn.GetToken: string;
1152 var
1153 Len: LongInt;
1154 begin
1155 Result := '';
1156 Len := Run - fTokenPos;
1157 SetString(Result, (FLine + fTokenPos), Len);
1158 end;
1159
GetTokenIDnull1160 function TSynPythonSyn.GetTokenID: TtkTokenKind;
1161 begin
1162 Result := fTokenId;
1163 end;
1164
GetTokenAttributenull1165 function TSynPythonSyn.GetTokenAttribute: TSynHighlighterAttributes;
1166 begin
1167 case fTokenID of
1168 tkComment: Result := fCommentAttri;
1169 tkIdentifier: Result := fIdentifierAttri;
1170 tkKey: Result := fKeyAttri;
1171 tkNonKeyword: Result := fNonKeyAttri;
1172 tkSystemDefined: Result := fSystemAttri;
1173 tkNumber: Result := fNumberAttri;
1174 tkHex: Result := fHexAttri;
1175 tkOct: Result := fOctalAttri;
1176 tkFloat: Result := fFloatAttri;
1177 tkSpace: Result := fSpaceAttri;
1178 tkString: Result := fStringAttri;
1179 tkTripleQuotedString: Result := fDocStringAttri;
1180 tkSymbol: Result := fSymbolAttri;
1181 tkUnknown: Result := fErrorAttri;
1182 else
1183 Result := nil;
1184 end;
1185 end;
1186
GetTokenKindnull1187 function TSynPythonSyn.GetTokenKind: integer;
1188 begin
1189 Result := Ord(fTokenId);
1190 end;
1191
TSynPythonSyn.GetTokenPosnull1192 function TSynPythonSyn.GetTokenPos: Integer;
1193 begin
1194 Result := fTokenPos;
1195 end;
1196
1197 procedure TSynPythonSyn.ResetRange;
1198 begin
1199 fRange := rsUnknown;
1200 end;
1201
1202 procedure TSynPythonSyn.SetRange(Value: Pointer);
1203 begin
1204 fRange := TRangeState(PtrUInt(Value));
1205 end;
1206
GetIdentCharsnull1207 function TSynPythonSyn.GetIdentChars: TSynIdentChars;
1208 begin
1209 Result := TSynValidStringChars;
1210 end;
1211
TSynPythonSyn.GetLanguageNamenull1212 class function TSynPythonSyn.GetLanguageName: string;
1213 begin
1214 Result := SYNS_LangPython;
1215 end;
1216
GetSampleSourcenull1217 function TSynPythonSyn.GetSampleSource: string;
1218 begin
1219 Result :=
1220 '#!/usr/local/bin/python'#13#10 +
1221 'import string, sys'#13#10 +
1222 '""" If no arguments were given, print a helpful message """'#13#10 +
1223 'if len(sys.argv)==1:'#13#10 +
1224 ' print ''Usage: celsius temp1 temp2 ...'''#13#10 +
1225 ' sys.exit(0)';
1226 end;
1227
1228 initialization
1229 RegisterPlaceableHighlighter(TSynPythonSyn);
1230
1231 finalization
1232 GlobalKeywords.Free;
1233 end.
1234
1235