1# -*- coding: utf-8 -*- 2""" 3 pygments.lexers.dylan 4 ~~~~~~~~~~~~~~~~~~~~~ 5 6 Lexers for the Dylan language. 7 8 :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS. 9 :license: BSD, see LICENSE for details. 10""" 11 12import re 13 14from pygments.lexer import Lexer, RegexLexer, bygroups, do_insertions, default 15from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ 16 Number, Punctuation, Generic, Literal 17 18__all__ = ['DylanLexer', 'DylanConsoleLexer', 'DylanLidLexer'] 19 20 21class 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 213class 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 242class 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 290