|
1 # -*- coding: utf-8 -*- |
|
2 """ |
|
3 pygments.lexers.dylan |
|
4 ~~~~~~~~~~~~~~~~~~~~~ |
|
5 |
|
6 Lexers for the Dylan language. |
|
7 |
|
8 :copyright: Copyright 2006-2014 by the Pygments team, see AUTHORS. |
|
9 :license: BSD, see LICENSE for details. |
|
10 """ |
|
11 |
|
12 import re |
|
13 |
|
14 from pygments.lexer import Lexer, RegexLexer, bygroups, do_insertions, default |
|
15 from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ |
|
16 Number, Punctuation, Generic, Literal |
|
17 |
|
18 __all__ = ['DylanLexer', 'DylanConsoleLexer', 'DylanLidLexer'] |
|
19 |
|
20 |
|
21 class DylanLexer(RegexLexer): |
|
22 """ |
|
23 For the `Dylan <http://www.opendylan.org/>`_ language. |
|
24 |
|
25 .. versionadded:: 0.7 |
|
26 """ |
|
27 |
|
28 name = 'Dylan' |
|
29 aliases = ['dylan'] |
|
30 filenames = ['*.dylan', '*.dyl', '*.intr'] |
|
31 mimetypes = ['text/x-dylan'] |
|
32 |
|
33 flags = re.IGNORECASE |
|
34 |
|
35 builtins = set(( |
|
36 'subclass', 'abstract', 'block', 'concrete', 'constant', 'class', |
|
37 'compiler-open', 'compiler-sideways', 'domain', 'dynamic', |
|
38 'each-subclass', 'exception', 'exclude', 'function', 'generic', |
|
39 'handler', 'inherited', 'inline', 'inline-only', 'instance', |
|
40 'interface', 'import', 'keyword', 'library', 'macro', 'method', |
|
41 'module', 'open', 'primary', 'required', 'sealed', 'sideways', |
|
42 'singleton', 'slot', 'thread', 'variable', 'virtual')) |
|
43 |
|
44 keywords = set(( |
|
45 'above', 'afterwards', 'begin', 'below', 'by', 'case', 'cleanup', |
|
46 'create', 'define', 'else', 'elseif', 'end', 'export', 'finally', |
|
47 'for', 'from', 'if', 'in', 'let', 'local', 'otherwise', 'rename', |
|
48 'select', 'signal', 'then', 'to', 'unless', 'until', 'use', 'when', |
|
49 'while')) |
|
50 |
|
51 operators = set(( |
|
52 '~', '+', '-', '*', '|', '^', '=', '==', '~=', '~==', '<', '<=', |
|
53 '>', '>=', '&', '|')) |
|
54 |
|
55 functions = set(( |
|
56 'abort', 'abs', 'add', 'add!', 'add-method', 'add-new', 'add-new!', |
|
57 'all-superclasses', 'always', 'any?', 'applicable-method?', 'apply', |
|
58 'aref', 'aref-setter', 'as', 'as-lowercase', 'as-lowercase!', |
|
59 'as-uppercase', 'as-uppercase!', 'ash', 'backward-iteration-protocol', |
|
60 'break', 'ceiling', 'ceiling/', 'cerror', 'check-type', 'choose', |
|
61 'choose-by', 'complement', 'compose', 'concatenate', 'concatenate-as', |
|
62 'condition-format-arguments', 'condition-format-string', 'conjoin', |
|
63 'copy-sequence', 'curry', 'default-handler', 'dimension', 'dimensions', |
|
64 'direct-subclasses', 'direct-superclasses', 'disjoin', 'do', |
|
65 'do-handlers', 'element', 'element-setter', 'empty?', 'error', 'even?', |
|
66 'every?', 'false-or', 'fill!', 'find-key', 'find-method', 'first', |
|
67 'first-setter', 'floor', 'floor/', 'forward-iteration-protocol', |
|
68 'function-arguments', 'function-return-values', |
|
69 'function-specializers', 'gcd', 'generic-function-mandatory-keywords', |
|
70 'generic-function-methods', 'head', 'head-setter', 'identity', |
|
71 'initialize', 'instance?', 'integral?', 'intersection', |
|
72 'key-sequence', 'key-test', 'last', 'last-setter', 'lcm', 'limited', |
|
73 'list', 'logand', 'logbit?', 'logior', 'lognot', 'logxor', 'make', |
|
74 'map', 'map-as', 'map-into', 'max', 'member?', 'merge-hash-codes', |
|
75 'min', 'modulo', 'negative', 'negative?', 'next-method', |
|
76 'object-class', 'object-hash', 'odd?', 'one-of', 'pair', 'pop', |
|
77 'pop-last', 'positive?', 'push', 'push-last', 'range', 'rank', |
|
78 'rcurry', 'reduce', 'reduce1', 'remainder', 'remove', 'remove!', |
|
79 'remove-duplicates', 'remove-duplicates!', 'remove-key!', |
|
80 'remove-method', 'replace-elements!', 'replace-subsequence!', |
|
81 'restart-query', 'return-allowed?', 'return-description', |
|
82 'return-query', 'reverse', 'reverse!', 'round', 'round/', |
|
83 'row-major-index', 'second', 'second-setter', 'shallow-copy', |
|
84 'signal', 'singleton', 'size', 'size-setter', 'slot-initialized?', |
|
85 'sort', 'sort!', 'sorted-applicable-methods', 'subsequence-position', |
|
86 'subtype?', 'table-protocol', 'tail', 'tail-setter', 'third', |
|
87 'third-setter', 'truncate', 'truncate/', 'type-error-expected-type', |
|
88 'type-error-value', 'type-for-copy', 'type-union', 'union', 'values', |
|
89 'vector', 'zero?')) |
|
90 |
|
91 valid_name = '\\\\?[\\w!&*<>|^$%@\\-+~?/=]+' |
|
92 |
|
93 def get_tokens_unprocessed(self, text): |
|
94 for index, token, value in RegexLexer.get_tokens_unprocessed(self, text): |
|
95 if token is Name: |
|
96 lowercase_value = value.lower() |
|
97 if lowercase_value in self.builtins: |
|
98 yield index, Name.Builtin, value |
|
99 continue |
|
100 if lowercase_value in self.keywords: |
|
101 yield index, Keyword, value |
|
102 continue |
|
103 if lowercase_value in self.functions: |
|
104 yield index, Name.Builtin, value |
|
105 continue |
|
106 if lowercase_value in self.operators: |
|
107 yield index, Operator, value |
|
108 continue |
|
109 yield index, token, value |
|
110 |
|
111 tokens = { |
|
112 'root': [ |
|
113 # Whitespace |
|
114 (r'\s+', Text), |
|
115 |
|
116 # single line comment |
|
117 (r'//.*?\n', Comment.Single), |
|
118 |
|
119 # lid header |
|
120 (r'([a-z0-9-]+)(:)([ \t]*)(.*(?:\n[ \t].+)*)', |
|
121 bygroups(Name.Attribute, Operator, Text, String)), |
|
122 |
|
123 default('code') # no header match, switch to code |
|
124 ], |
|
125 'code': [ |
|
126 # Whitespace |
|
127 (r'\s+', Text), |
|
128 |
|
129 # single line comment |
|
130 (r'//.*?\n', Comment.Single), |
|
131 |
|
132 # multi-line comment |
|
133 (r'/\*', Comment.Multiline, 'comment'), |
|
134 |
|
135 # strings and characters |
|
136 (r'"', String, 'string'), |
|
137 (r"'(\\.|\\[0-7]{1,3}|\\x[a-f0-9]{1,2}|[^\\\'\n])'", String.Char), |
|
138 |
|
139 # binary integer |
|
140 (r'#b[01]+', Number.Bin), |
|
141 |
|
142 # octal integer |
|
143 (r'#o[0-7]+', Number.Oct), |
|
144 |
|
145 # floating point |
|
146 (r'[-+]?(\d*\.\d+(e[-+]?\d+)?|\d+(\.\d*)?e[-+]?\d+)', Number.Float), |
|
147 |
|
148 # decimal integer |
|
149 (r'[-+]?\d+', Number.Integer), |
|
150 |
|
151 # hex integer |
|
152 (r'#x[0-9a-f]+', Number.Hex), |
|
153 |
|
154 # Macro parameters |
|
155 (r'(\?' + valid_name + ')(:)' |
|
156 r'(token|name|variable|expression|body|case-body|\*)', |
|
157 bygroups(Name.Tag, Operator, Name.Builtin)), |
|
158 (r'(\?)(:)(token|name|variable|expression|body|case-body|\*)', |
|
159 bygroups(Name.Tag, Operator, Name.Builtin)), |
|
160 (r'\?' + valid_name, Name.Tag), |
|
161 |
|
162 # Punctuation |
|
163 (r'(=>|::|#\(|#\[|##|\?\?|\?=|\?|[(){}\[\],.;])', Punctuation), |
|
164 |
|
165 # Most operators are picked up as names and then re-flagged. |
|
166 # This one isn't valid in a name though, so we pick it up now. |
|
167 (r':=', Operator), |
|
168 |
|
169 # Pick up #t / #f before we match other stuff with #. |
|
170 (r'#[tf]', Literal), |
|
171 |
|
172 # #"foo" style keywords |
|
173 (r'#"', String.Symbol, 'keyword'), |
|
174 |
|
175 # #rest, #key, #all-keys, etc. |
|
176 (r'#[a-z0-9-]+', Keyword), |
|
177 |
|
178 # required-init-keyword: style keywords. |
|
179 (valid_name + ':', Keyword), |
|
180 |
|
181 # class names |
|
182 (r'<' + valid_name + '>', Name.Class), |
|
183 |
|
184 # define variable forms. |
|
185 (r'\*' + valid_name + '\*', Name.Variable.Global), |
|
186 |
|
187 # define constant forms. |
|
188 (r'\$' + valid_name, Name.Constant), |
|
189 |
|
190 # everything else. We re-flag some of these in the method above. |
|
191 (valid_name, Name), |
|
192 ], |
|
193 'comment': [ |
|
194 (r'[^*/]', Comment.Multiline), |
|
195 (r'/\*', Comment.Multiline, '#push'), |
|
196 (r'\*/', Comment.Multiline, '#pop'), |
|
197 (r'[*/]', Comment.Multiline) |
|
198 ], |
|
199 'keyword': [ |
|
200 (r'"', String.Symbol, '#pop'), |
|
201 (r'[^\\"]+', String.Symbol), # all other characters |
|
202 ], |
|
203 'string': [ |
|
204 (r'"', String, '#pop'), |
|
205 (r'\\([\\abfnrtv"\']|x[a-f0-9]{2,4}|[0-7]{1,3})', String.Escape), |
|
206 (r'[^\\"\n]+', String), # all other characters |
|
207 (r'\\\n', String), # line continuation |
|
208 (r'\\', String), # stray backslash |
|
209 ] |
|
210 } |
|
211 |
|
212 |
|
213 class DylanLidLexer(RegexLexer): |
|
214 """ |
|
215 For Dylan LID (Library Interchange Definition) files. |
|
216 |
|
217 .. versionadded:: 1.6 |
|
218 """ |
|
219 |
|
220 name = 'DylanLID' |
|
221 aliases = ['dylan-lid', 'lid'] |
|
222 filenames = ['*.lid', '*.hdp'] |
|
223 mimetypes = ['text/x-dylan-lid'] |
|
224 |
|
225 flags = re.IGNORECASE |
|
226 |
|
227 tokens = { |
|
228 'root': [ |
|
229 # Whitespace |
|
230 (r'\s+', Text), |
|
231 |
|
232 # single line comment |
|
233 (r'//.*?\n', Comment.Single), |
|
234 |
|
235 # lid header |
|
236 (r'(.*?)(:)([ \t]*)(.*(?:\n[ \t].+)*)', |
|
237 bygroups(Name.Attribute, Operator, Text, String)), |
|
238 ] |
|
239 } |
|
240 |
|
241 |
|
242 class DylanConsoleLexer(Lexer): |
|
243 """ |
|
244 For Dylan interactive console output like: |
|
245 |
|
246 .. sourcecode:: dylan-console |
|
247 |
|
248 ? let a = 1; |
|
249 => 1 |
|
250 ? a |
|
251 => 1 |
|
252 |
|
253 This is based on a copy of the RubyConsoleLexer. |
|
254 |
|
255 .. versionadded:: 1.6 |
|
256 """ |
|
257 name = 'Dylan session' |
|
258 aliases = ['dylan-console', 'dylan-repl'] |
|
259 filenames = ['*.dylan-console'] |
|
260 mimetypes = ['text/x-dylan-console'] |
|
261 |
|
262 _line_re = re.compile('.*?\n') |
|
263 _prompt_re = re.compile('\?| ') |
|
264 |
|
265 def get_tokens_unprocessed(self, text): |
|
266 dylexer = DylanLexer(**self.options) |
|
267 |
|
268 curcode = '' |
|
269 insertions = [] |
|
270 for match in self._line_re.finditer(text): |
|
271 line = match.group() |
|
272 m = self._prompt_re.match(line) |
|
273 if m is not None: |
|
274 end = m.end() |
|
275 insertions.append((len(curcode), |
|
276 [(0, Generic.Prompt, line[:end])])) |
|
277 curcode += line[end:] |
|
278 else: |
|
279 if curcode: |
|
280 for item in do_insertions(insertions, |
|
281 dylexer.get_tokens_unprocessed(curcode)): |
|
282 yield item |
|
283 curcode = '' |
|
284 insertions = [] |
|
285 yield match.start(), Generic.Output, line |
|
286 if curcode: |
|
287 for item in do_insertions(insertions, |
|
288 dylexer.get_tokens_unprocessed(curcode)): |
|
289 yield item |