Gridarta Editor
PythonTokenMarker.java
Go to the documentation of this file.
1 /*
2  * PythonTokenMarker.java - Python token marker
3  * Copyright (C) 1999 Jonathan Revusky
4  * Copyright (C) 1998, 1999 Slava Pestov
5  * Copyright (C) 2000-2023 The Gridarta Developers.
6  *
7  * You may use and modify this package for any purpose. Redistribution is
8  * permitted, in both source and binary form, provided that this notice
9  * remains intact in all source distributions of this package.
10  */
11 
12 package net.sf.gridarta.textedit.textarea.tokenmarker;
13 
14 import javax.swing.text.Segment;
17 import org.jetbrains.annotations.NotNull;
18 import org.jetbrains.annotations.Nullable;
19 
24 public class PythonTokenMarker extends TokenMarker {
25 
26  private static final byte TRIPLE_QUOTE1 = Token.INTERNAL_FIRST;
27 
28  private static final byte TRIPLE_QUOTE2 = Token.INTERNAL_LAST;
29 
30  @Nullable
31  private static KeywordMap pythonKeywords;
32 
33  @NotNull
34  private final KeywordMap keywords;
35 
36  private int lastOffset;
37 
38  private int lastKeyword;
39 
40  public PythonTokenMarker() {
42  }
43 
44  @Override
45  public byte markTokensImpl(final byte token, @NotNull final Segment line) {
46  final char[] array = line.array;
47  final int offset = line.offset;
48  lastOffset = offset;
49  lastKeyword = offset;
50  final int length = line.count + offset;
51  boolean backslash = false;
52 
53  byte currentToken = token;
54 loop:
55  for (int i = offset; i < length; i++) {
56  final int i1 = i + 1;
57 
58  final char c = array[i];
59  if (c == '\\') {
60  backslash = !backslash;
61  continue;
62  }
63 
64  switch (currentToken) {
65  case Token.NULL:
66  switch (c) {
67  case '#':
68  if (backslash) {
69  backslash = false;
70  } else {
71  doKeyword(line, i);
72  addToken(i - lastOffset, currentToken);
76  break loop;
77  }
78  break;
79 
80  case '"':
81  doKeyword(line, i);
82  if (backslash) {
83  backslash = false;
84  } else {
85  addToken(i - lastOffset, currentToken);
86  currentToken = SyntaxUtilities.regionMatches(false, line, i1, "\"\"") ? TRIPLE_QUOTE1 : Token.LITERAL1;
87  lastOffset = i;
88  lastKeyword = i;
89  }
90  break;
91 
92  case '\'':
93  doKeyword(line, i);
94  if (backslash) {
95  backslash = false;
96  } else {
97  addToken(i - lastOffset, currentToken);
98  currentToken = SyntaxUtilities.regionMatches(false, line, i1, "''") ? TRIPLE_QUOTE2 : Token.LITERAL2;
99  lastOffset = i;
100  lastKeyword = i;
101  }
102  break;
103 
104  default:
105  backslash = false;
106  if (!Character.isLetterOrDigit(c) && c != '_') {
107  doKeyword(line, i);
108  }
109  break;
110  }
111  break;
112 
113  case Token.LITERAL1:
114  if (backslash) {
115  backslash = false;
116  } else if (c == '"') {
117  addToken(i1 - lastOffset, currentToken);
118  currentToken = Token.NULL;
119  lastOffset = i1;
120  lastKeyword = i1;
121  }
122  break;
123 
124  case Token.LITERAL2:
125  if (backslash) {
126  backslash = false;
127  } else if (c == '\'') {
129  currentToken = Token.NULL;
130  lastOffset = i1;
131  lastKeyword = i1;
132  }
133  break;
134 
135  case TRIPLE_QUOTE1:
136  if (backslash) {
137  backslash = false;
138  } else if (SyntaxUtilities.regionMatches(false, line, i, "\"\"\"")) {
139  i += 4;
141  currentToken = Token.NULL;
142  lastOffset = i;
143  lastKeyword = i;
144  }
145  break;
146 
147  case TRIPLE_QUOTE2:
148  if (backslash) {
149  backslash = false;
150  } else if (SyntaxUtilities.regionMatches(false, line, i, "'''")) {
151  i += 4;
153  currentToken = Token.NULL;
154  lastOffset = i;
155  lastKeyword = i;
156  }
157  break;
158 
159  default:
160  throw new InternalError("Invalid state: " + currentToken);
161  }
162  }
163 
164  switch (currentToken) {
165  case TRIPLE_QUOTE1:
166  case TRIPLE_QUOTE2:
168  break;
169 
170  case Token.NULL:
171  doKeyword(line, length);
172 
173  default:
174  addToken(length - lastOffset, currentToken);
175  break;
176  }
177 
178  return currentToken;
179  }
180 
181  @NotNull
182  private static KeywordMap getPythonKeywords() {
183  if (pythonKeywords == null) {
184  pythonKeywords = new KeywordMap(false);
190  pythonKeywords.add("assert", Token.KEYWORD1);
191  pythonKeywords.add("break", Token.KEYWORD1);
192  pythonKeywords.add("continue", Token.KEYWORD1);
193  pythonKeywords.add("elif", Token.KEYWORD1);
194  pythonKeywords.add("else", Token.KEYWORD1);
195  pythonKeywords.add("except", Token.KEYWORD1);
196  pythonKeywords.add("exec", Token.KEYWORD1);
197  pythonKeywords.add("finally", Token.KEYWORD1);
198  pythonKeywords.add("raise", Token.KEYWORD1);
199  pythonKeywords.add("return", Token.KEYWORD1);
201  pythonKeywords.add("while", Token.KEYWORD1);
202  pythonKeywords.add("yield", Token.KEYWORD1);
205  pythonKeywords.add("class", Token.KEYWORD2);
207  pythonKeywords.add("from", Token.KEYWORD2);
208  pythonKeywords.add("global", Token.KEYWORD2);
209  pythonKeywords.add("import", Token.KEYWORD2);
212  pythonKeywords.add("lambda", Token.KEYWORD2);
213  pythonKeywords.add("pass", Token.KEYWORD2);
214  pythonKeywords.add("print", Token.KEYWORD2);
215  pythonKeywords.add("with", Token.KEYWORD2);
216  }
217  return pythonKeywords;
218  }
219 
220  private void doKeyword(@NotNull final Segment line, final int i) {
221  final int len = i - lastKeyword;
222  final byte id = keywords.lookup(line, lastKeyword, len);
223  if (id != Token.NULL) {
224  if (lastKeyword != lastOffset) {
226  }
227  addToken(len, id);
228  lastOffset = i;
229  }
230  lastKeyword = i + 1;
231  }
232 
233 }
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.TRIPLE_QUOTE2
static final byte TRIPLE_QUOTE2
Definition: PythonTokenMarker.java:28
net.sf.gridarta.textedit.textarea.Token.INTERNAL_FIRST
static final byte INTERNAL_FIRST
The first id that can be used for internal state in a token marker.
Definition: Token.java:94
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.PythonTokenMarker
PythonTokenMarker()
Definition: PythonTokenMarker.java:40
net.sf.gridarta.textedit.textarea
This package contains the other part of the script editor.
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.textedit.textarea.tokenmarker.TokenMarker.addToken
void addToken(final int length, final byte id)
Adds a token to the token list.
Definition: TokenMarker.java:225
net.sf.gridarta.textedit.textarea.Token.NULL
static final byte NULL
Normal text token id.
Definition: Token.java:26
net.sf
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.keywords
final KeywordMap keywords
Definition: PythonTokenMarker.java:34
net.sf.gridarta.textedit.textarea.tokenmarker.KeywordMap.lookup
byte lookup(final Segment text, final int offset, final int length)
Looks up a key.
Definition: KeywordMap.java:63
net.sf.gridarta.textedit
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.pythonKeywords
static KeywordMap pythonKeywords
Definition: PythonTokenMarker.java:31
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.TRIPLE_QUOTE1
static final byte TRIPLE_QUOTE1
Definition: PythonTokenMarker.java:26
net.sf.gridarta.textedit.textarea.SyntaxUtilities.regionMatches
static boolean regionMatches(final boolean ignoreCase, final Segment text, final int offset, @NotNull final CharSequence match)
Checks if a sub-region of a.
Definition: SyntaxUtilities.java:43
net.sf.gridarta.textedit.textarea.tokenmarker.KeywordMap.add
void add(final CharSequence keyword, final byte id)
Adds a key-value mapping.
Definition: KeywordMap.java:79
net.sf.gridarta.textedit.textarea.Token.LITERAL2
static final byte LITERAL2
Literal 2 token id.
Definition: Token.java:48
net.sf.gridarta.textedit.textarea.Token
A linked list of tokens.
Definition: Token.java:21
net.sf.gridarta.textedit.textarea.Token.INTERNAL_LAST
static final byte INTERNAL_LAST
The last id that can be used for internal state in a token marker.
Definition: Token.java:99
net
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.doKeyword
void doKeyword(@NotNull final Segment line, final int i)
Definition: PythonTokenMarker.java:220
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.markTokensImpl
byte markTokensImpl(final byte token, @NotNull final Segment line)
An abstract method that splits a line up into tokens.
Definition: PythonTokenMarker.java:45
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker
Python token marker.
Definition: PythonTokenMarker.java:24
net.sf.gridarta.textedit.textarea.Token.KEYWORD2
static final byte KEYWORD2
Keyword 2 token id.
Definition: Token.java:66
net.sf.gridarta.textedit.textarea.Token.KEYWORD1
static final byte KEYWORD1
Keyword 1 token id.
Definition: Token.java:60
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.lastOffset
int lastOffset
Definition: PythonTokenMarker.java:36
net.sf.gridarta.textedit.textarea.Token.KEYWORD3
static final byte KEYWORD3
Keyword 3 token id.
Definition: Token.java:72
net.sf.gridarta.textedit.textarea.tokenmarker.KeywordMap
Maps (parts of) Segments to.
Definition: KeywordMap.java:35
net.sf.gridarta.textedit.textarea.SyntaxUtilities
Class with several utility functions used by jEdit's syntax colorizing subsystem.
Definition: SyntaxUtilities.java:27
net.sf.gridarta.textedit.textarea.Token.LITERAL1
static final byte LITERAL1
Literal 1 token id.
Definition: Token.java:42
net.sf.gridarta.textedit.textarea.tokenmarker.TokenMarker
A token marker that splits lines of text into tokens.
Definition: TokenMarker.java:32
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.lastKeyword
int lastKeyword
Definition: PythonTokenMarker.java:38
net.sf.gridarta.textedit.textarea.Token.COMMENT1
static final byte COMMENT1
Comment 1 token id.
Definition: Token.java:31
net.sf.gridarta.textedit.textarea.tokenmarker.TokenMarker.length
int length
The number of lines in the model being tokenized.
Definition: TokenMarker.java:52
net.sf.gridarta.textedit.textarea.tokenmarker.PythonTokenMarker.getPythonKeywords
static KeywordMap getPythonKeywords()
Definition: PythonTokenMarker.java:182