| """ |
| pygments.lexers.haskell |
| ~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Lexers for Haskell and related languages. |
| |
| :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. |
| :license: BSD, see LICENSE for details. |
| """ |
| |
| import re |
| |
| from pygments.lexer import Lexer, RegexLexer, bygroups, do_insertions, \ |
| default, include, inherit, line_re |
| from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ |
| Number, Punctuation, Generic, Whitespace |
| from pygments import unistring as uni |
| |
| __all__ = ['HaskellLexer', 'HspecLexer', 'IdrisLexer', 'AgdaLexer', 'CryptolLexer', |
| 'LiterateHaskellLexer', 'LiterateIdrisLexer', 'LiterateAgdaLexer', |
| 'LiterateCryptolLexer', 'KokaLexer'] |
| |
| |
| class HaskellLexer(RegexLexer): |
| """ |
| A Haskell lexer based on the lexemes defined in the Haskell 98 Report. |
| |
| .. versionadded:: 0.8 |
| """ |
| name = 'Haskell' |
| url = 'https://www.haskell.org/' |
| aliases = ['haskell', 'hs'] |
| filenames = ['*.hs'] |
| mimetypes = ['text/x-haskell'] |
| |
| reserved = ('case', 'class', 'data', 'default', 'deriving', 'do', 'else', |
| 'family', 'if', 'in', 'infix[lr]?', 'instance', |
| 'let', 'newtype', 'of', 'then', 'type', 'where', '_') |
| ascii = ('NUL', 'SOH', '[SE]TX', 'EOT', 'ENQ', 'ACK', |
| 'BEL', 'BS', 'HT', 'LF', 'VT', 'FF', 'CR', 'S[OI]', 'DLE', |
| 'DC[1-4]', 'NAK', 'SYN', 'ETB', 'CAN', |
| 'EM', 'SUB', 'ESC', '[FGRU]S', 'SP', 'DEL') |
| |
| tokens = { |
| 'root': [ |
| # Whitespace: |
| (r'\s+', Whitespace), |
| # (r'--\s*|.*$', Comment.Doc), |
| (r'--(?![!#$%&*+./<=>?@^|_~:\\]).*?$', Comment.Single), |
| (r'\{-', Comment.Multiline, 'comment'), |
| # Lexemes: |
| # Identifiers |
| (r'\bimport\b', Keyword.Reserved, 'import'), |
| (r'\bmodule\b', Keyword.Reserved, 'module'), |
| (r'\berror\b', Name.Exception), |
| (r'\b(%s)(?!\')\b' % '|'.join(reserved), Keyword.Reserved), |
| (r"'[^\\]'", String.Char), # this has to come before the TH quote |
| (r'^[_' + uni.Ll + r'][\w\']*', Name.Function), |
| (r"'?[_" + uni.Ll + r"][\w']*", Name), |
| (r"('')?[" + uni.Lu + r"][\w\']*", Keyword.Type), |
| (r"(')[" + uni.Lu + r"][\w\']*", Keyword.Type), |
| (r"(')\[[^\]]*\]", Keyword.Type), # tuples and lists get special treatment in GHC |
| (r"(')\([^)]*\)", Keyword.Type), # .. |
| (r"(')[:!#$%&*+.\\/<=>?@^|~-]+", Keyword.Type), # promoted type operators |
| # Operators |
| (r'\\(?![:!#$%&*+.\\/<=>?@^|~-]+)', Name.Function), # lambda operator |
| (r'(<-|::|->|=>|=)(?![:!#$%&*+.\\/<=>?@^|~-]+)', Operator.Word), # specials |
| (r':[:!#$%&*+.\\/<=>?@^|~-]*', Keyword.Type), # Constructor operators |
| (r'[:!#$%&*+.\\/<=>?@^|~-]+', Operator), # Other operators |
| # Numbers |
| (r'0[xX]_*[\da-fA-F](_*[\da-fA-F])*_*[pP][+-]?\d(_*\d)*', Number.Float), |
| (r'0[xX]_*[\da-fA-F](_*[\da-fA-F])*\.[\da-fA-F](_*[\da-fA-F])*' |
| r'(_*[pP][+-]?\d(_*\d)*)?', Number.Float), |
| (r'\d(_*\d)*_*[eE][+-]?\d(_*\d)*', Number.Float), |
| (r'\d(_*\d)*\.\d(_*\d)*(_*[eE][+-]?\d(_*\d)*)?', Number.Float), |
| (r'0[bB]_*[01](_*[01])*', Number.Bin), |
| (r'0[oO]_*[0-7](_*[0-7])*', Number.Oct), |
| (r'0[xX]_*[\da-fA-F](_*[\da-fA-F])*', Number.Hex), |
| (r'\d(_*\d)*', Number.Integer), |
| # Character/String Literals |
| (r"'", String.Char, 'character'), |
| (r'"', String, 'string'), |
| # Special |
| (r'\[\]', Keyword.Type), |
| (r'\(\)', Name.Builtin), |
| (r'[][(),;`{}]', Punctuation), |
| ], |
| 'import': [ |
| # Import statements |
| (r'\s+', Whitespace), |
| (r'"', String, 'string'), |
| # after "funclist" state |
| (r'\)', Punctuation, '#pop'), |
| (r'qualified\b', Keyword), |
| # import X as Y |
| (r'([' + uni.Lu + r'][\w.]*)(\s+)(as)(\s+)([' + uni.Lu + r'][\w.]*)', |
| bygroups(Name.Namespace, Whitespace, Keyword, Whitespace, Name), '#pop'), |
| # import X hiding (functions) |
| (r'([' + uni.Lu + r'][\w.]*)(\s+)(hiding)(\s+)(\()', |
| bygroups(Name.Namespace, Whitespace, Keyword, Whitespace, Punctuation), 'funclist'), |
| # import X (functions) |
| (r'([' + uni.Lu + r'][\w.]*)(\s+)(\()', |
| bygroups(Name.Namespace, Whitespace, Punctuation), 'funclist'), |
| # import X |
| (r'[\w.]+', Name.Namespace, '#pop'), |
| ], |
| 'module': [ |
| (r'\s+', Whitespace), |
| (r'([' + uni.Lu + r'][\w.]*)(\s+)(\()', |
| bygroups(Name.Namespace, Whitespace, Punctuation), 'funclist'), |
| (r'[' + uni.Lu + r'][\w.]*', Name.Namespace, '#pop'), |
| ], |
| 'funclist': [ |
| (r'\s+', Whitespace), |
| (r'[' + uni.Lu + r']\w*', Keyword.Type), |
| (r'(_[\w\']+|[' + uni.Ll + r'][\w\']*)', Name.Function), |
| (r'--(?![!#$%&*+./<=>?@^|_~:\\]).*?$', Comment.Single), |
| (r'\{-', Comment.Multiline, 'comment'), |
| (r',', Punctuation), |
| (r'[:!#$%&*+.\\/<=>?@^|~-]+', Operator), |
| # (HACK, but it makes sense to push two instances, believe me) |
| (r'\(', Punctuation, ('funclist', 'funclist')), |
| (r'\)', Punctuation, '#pop:2'), |
| ], |
| # NOTE: the next four states are shared in the AgdaLexer; make sure |
| # any change is compatible with Agda as well or copy over and change |
| 'comment': [ |
| # Multiline Comments |
| (r'[^-{}]+', Comment.Multiline), |
| (r'\{-', Comment.Multiline, '#push'), |
| (r'-\}', Comment.Multiline, '#pop'), |
| (r'[-{}]', Comment.Multiline), |
| ], |
| 'character': [ |
| # Allows multi-chars, incorrectly. |
| (r"[^\\']'", String.Char, '#pop'), |
| (r"\\", String.Escape, 'escape'), |
| ("'", String.Char, '#pop'), |
| ], |
| 'string': [ |
| (r'[^\\"]+', String), |
| (r"\\", String.Escape, 'escape'), |
| ('"', String, '#pop'), |
| ], |
| 'escape': [ |
| (r'[abfnrtv"\'&\\]', String.Escape, '#pop'), |
| (r'\^[][' + uni.Lu + r'@^_]', String.Escape, '#pop'), |
| ('|'.join(ascii), String.Escape, '#pop'), |
| (r'o[0-7]+', String.Escape, '#pop'), |
| (r'x[\da-fA-F]+', String.Escape, '#pop'), |
| (r'\d+', String.Escape, '#pop'), |
| (r'(\s+)(\\)', bygroups(Whitespace, String.Escape), '#pop'), |
| ], |
| } |
| |
| |
| class HspecLexer(HaskellLexer): |
| """ |
| A Haskell lexer with support for Hspec constructs. |
| |
| .. versionadded:: 2.4.0 |
| """ |
| |
| name = 'Hspec' |
| aliases = ['hspec'] |
| filenames = ['*Spec.hs'] |
| mimetypes = [] |
| |
| tokens = { |
| 'root': [ |
| (r'(it)(\s*)("[^"]*")', bygroups(Text, Whitespace, String.Doc)), |
| (r'(describe)(\s*)("[^"]*")', bygroups(Text, Whitespace, String.Doc)), |
| (r'(context)(\s*)("[^"]*")', bygroups(Text, Whitespace, String.Doc)), |
| inherit, |
| ], |
| } |
| |
| |
| class IdrisLexer(RegexLexer): |
| """ |
| A lexer for the dependently typed programming language Idris. |
| |
| Based on the Haskell and Agda Lexer. |
| |
| .. versionadded:: 2.0 |
| """ |
| name = 'Idris' |
| url = 'https://www.idris-lang.org/' |
| aliases = ['idris', 'idr'] |
| filenames = ['*.idr'] |
| mimetypes = ['text/x-idris'] |
| |
| reserved = ('case', 'class', 'data', 'default', 'using', 'do', 'else', |
| 'if', 'in', 'infix[lr]?', 'instance', 'rewrite', 'auto', |
| 'namespace', 'codata', 'mutual', 'private', 'public', 'abstract', |
| 'total', 'partial', |
| 'interface', 'implementation', 'export', 'covering', 'constructor', |
| 'let', 'proof', 'of', 'then', 'static', 'where', '_', 'with', |
| 'pattern', 'term', 'syntax', 'prefix', |
| 'postulate', 'parameters', 'record', 'dsl', 'impossible', 'implicit', |
| 'tactics', 'intros', 'intro', 'compute', 'refine', 'exact', 'trivial') |
| |
| ascii = ('NUL', 'SOH', '[SE]TX', 'EOT', 'ENQ', 'ACK', |
| 'BEL', 'BS', 'HT', 'LF', 'VT', 'FF', 'CR', 'S[OI]', 'DLE', |
| 'DC[1-4]', 'NAK', 'SYN', 'ETB', 'CAN', |
| 'EM', 'SUB', 'ESC', '[FGRU]S', 'SP', 'DEL') |
| |
| directives = ('lib', 'link', 'flag', 'include', 'hide', 'freeze', 'access', |
| 'default', 'logging', 'dynamic', 'name', 'error_handlers', 'language') |
| |
| tokens = { |
| 'root': [ |
| # Comments |
| (r'^(\s*)(%%(%s))' % '|'.join(directives), |
| bygroups(Whitespace, Keyword.Reserved)), |
| (r'(\s*)(--(?![!#$%&*+./<=>?@^|_~:\\]).*?)$', bygroups(Whitespace, Comment.Single)), |
| (r'(\s*)(\|{3}.*?)$', bygroups(Whitespace, Comment.Single)), |
| (r'(\s*)(\{-)', bygroups(Whitespace, Comment.Multiline), 'comment'), |
| # Declaration |
| (r'^(\s*)([^\s(){}]+)(\s*)(:)(\s*)', |
| bygroups(Whitespace, Name.Function, Whitespace, Operator.Word, Whitespace)), |
| # Identifiers |
| (r'\b(%s)(?!\')\b' % '|'.join(reserved), Keyword.Reserved), |
| (r'(import|module)(\s+)', bygroups(Keyword.Reserved, Whitespace), 'module'), |
| (r"('')?[A-Z][\w\']*", Keyword.Type), |
| (r'[a-z][\w\']*', Text), |
| # Special Symbols |
| (r'(<-|::|->|=>|=)', Operator.Word), # specials |
| (r'([(){}\[\]:!#$%&*+.\\/<=>?@^|~-]+)', Operator.Word), # specials |
| # Numbers |
| (r'\d+[eE][+-]?\d+', Number.Float), |
| (r'\d+\.\d+([eE][+-]?\d+)?', Number.Float), |
| (r'0[xX][\da-fA-F]+', Number.Hex), |
| (r'\d+', Number.Integer), |
| # Strings |
| (r"'", String.Char, 'character'), |
| (r'"', String, 'string'), |
| (r'[^\s(){}]+', Text), |
| (r'\s+?', Whitespace), # Whitespace |
| ], |
| 'module': [ |
| (r'\s+', Whitespace), |
| (r'([A-Z][\w.]*)(\s+)(\()', |
| bygroups(Name.Namespace, Whitespace, Punctuation), 'funclist'), |
| (r'[A-Z][\w.]*', Name.Namespace, '#pop'), |
| ], |
| 'funclist': [ |
| (r'\s+', Whitespace), |
| (r'[A-Z]\w*', Keyword.Type), |
| (r'(_[\w\']+|[a-z][\w\']*)', Name.Function), |
| (r'--.*$', Comment.Single), |
| (r'\{-', Comment.Multiline, 'comment'), |
| (r',', Punctuation), |
| (r'[:!#$%&*+.\\/<=>?@^|~-]+', Operator), |
| # (HACK, but it makes sense to push two instances, believe me) |
| (r'\(', Punctuation, ('funclist', 'funclist')), |
| (r'\)', Punctuation, '#pop:2'), |
| ], |
| # NOTE: the next four states are shared in the AgdaLexer; make sure |
| # any change is compatible with Agda as well or copy over and change |
| 'comment': [ |
| # Multiline Comments |
| (r'[^-{}]+', Comment.Multiline), |
| (r'\{-', Comment.Multiline, '#push'), |
| (r'-\}', Comment.Multiline, '#pop'), |
| (r'[-{}]', Comment.Multiline), |
| ], |
| 'character': [ |
| # Allows multi-chars, incorrectly. |
| (r"[^\\']", String.Char), |
| (r"\\", String.Escape, 'escape'), |
| ("'", String.Char, '#pop'), |
| ], |
| 'string': [ |
| (r'[^\\"]+', String), |
| (r"\\", String.Escape, 'escape'), |
| ('"', String, '#pop'), |
| ], |
| 'escape': [ |
| (r'[abfnrtv"\'&\\]', String.Escape, '#pop'), |
| (r'\^[][A-Z@^_]', String.Escape, '#pop'), |
| ('|'.join(ascii), String.Escape, '#pop'), |
| (r'o[0-7]+', String.Escape, '#pop'), |
| (r'x[\da-fA-F]+', String.Escape, '#pop'), |
| (r'\d+', String.Escape, '#pop'), |
| (r'(\s+)(\\)', bygroups(Whitespace, String.Escape), '#pop') |
| ], |
| } |
| |
| |
| class AgdaLexer(RegexLexer): |
| """ |
| For the Agda dependently typed functional programming language and |
| proof assistant. |
| |
| .. versionadded:: 2.0 |
| """ |
| |
| name = 'Agda' |
| url = 'http://wiki.portal.chalmers.se/agda/pmwiki.php' |
| aliases = ['agda'] |
| filenames = ['*.agda'] |
| mimetypes = ['text/x-agda'] |
| |
| reserved = ( |
| 'abstract', 'codata', 'coinductive', 'constructor', 'data', 'do', |
| 'eta-equality', 'field', 'forall', 'hiding', 'in', 'inductive', 'infix', |
| 'infixl', 'infixr', 'instance', 'interleaved', 'let', 'macro', 'mutual', |
| 'no-eta-equality', 'open', 'overlap', 'pattern', 'postulate', 'primitive', |
| 'private', 'quote', 'quoteTerm', 'record', 'renaming', 'rewrite', |
| 'syntax', 'tactic', 'unquote', 'unquoteDecl', 'unquoteDef', 'using', |
| 'variable', 'where', 'with', |
| ) |
| |
| tokens = { |
| 'root': [ |
| # Declaration |
| (r'^(\s*)([^\s(){}]+)(\s*)(:)(\s*)', |
| bygroups(Whitespace, Name.Function, Whitespace, |
| Operator.Word, Whitespace)), |
| # Comments |
| (r'--(?![!#$%&*+./<=>?@^|_~:\\]).*?$', Comment.Single), |
| (r'\{-', Comment.Multiline, 'comment'), |
| # Holes |
| (r'\{!', Comment.Directive, 'hole'), |
| # Lexemes: |
| # Identifiers |
| (r'\b(%s)(?!\')\b' % '|'.join(reserved), Keyword.Reserved), |
| (r'(import|module)(\s+)', bygroups(Keyword.Reserved, Whitespace), |
| 'module'), |
| (r'\b(Set|Prop)[\u2080-\u2089]*\b', Keyword.Type), |
| # Special Symbols |
| (r'(\(|\)|\{|\})', Operator), |
| (r'(\.{1,3}|\||\u03BB|\u2200|\u2192|:|=|->)', Operator.Word), |
| # Numbers |
| (r'\d+[eE][+-]?\d+', Number.Float), |
| (r'\d+\.\d+([eE][+-]?\d+)?', Number.Float), |
| (r'0[xX][\da-fA-F]+', Number.Hex), |
| (r'\d+', Number.Integer), |
| # Strings |
| (r"'", String.Char, 'character'), |
| (r'"', String, 'string'), |
| (r'[^\s(){}]+', Text), |
| (r'\s+?', Whitespace), # Whitespace |
| ], |
| 'hole': [ |
| # Holes |
| (r'[^!{}]+', Comment.Directive), |
| (r'\{!', Comment.Directive, '#push'), |
| (r'!\}', Comment.Directive, '#pop'), |
| (r'[!{}]', Comment.Directive), |
| ], |
| 'module': [ |
| (r'\{-', Comment.Multiline, 'comment'), |
| (r'[a-zA-Z][\w.\']*', Name, '#pop'), |
| (r'[\W0-9_]+', Text) |
| ], |
| 'comment': HaskellLexer.tokens['comment'], |
| 'character': HaskellLexer.tokens['character'], |
| 'string': HaskellLexer.tokens['string'], |
| 'escape': HaskellLexer.tokens['escape'] |
| } |
| |
| |
| class CryptolLexer(RegexLexer): |
| """ |
| FIXME: A Cryptol2 lexer based on the lexemes defined in the Haskell 98 Report. |
| |
| .. versionadded:: 2.0 |
| """ |
| name = 'Cryptol' |
| aliases = ['cryptol', 'cry'] |
| filenames = ['*.cry'] |
| mimetypes = ['text/x-cryptol'] |
| |
| reserved = ('Arith', 'Bit', 'Cmp', 'False', 'Inf', 'True', 'else', |
| 'export', 'extern', 'fin', 'if', 'import', 'inf', 'lg2', |
| 'max', 'min', 'module', 'newtype', 'pragma', 'property', |
| 'then', 'type', 'where', 'width') |
| ascii = ('NUL', 'SOH', '[SE]TX', 'EOT', 'ENQ', 'ACK', |
| 'BEL', 'BS', 'HT', 'LF', 'VT', 'FF', 'CR', 'S[OI]', 'DLE', |
| 'DC[1-4]', 'NAK', 'SYN', 'ETB', 'CAN', |
| 'EM', 'SUB', 'ESC', '[FGRU]S', 'SP', 'DEL') |
| |
| tokens = { |
| 'root': [ |
| # Whitespace: |
| (r'\s+', Whitespace), |
| # (r'--\s*|.*$', Comment.Doc), |
| (r'//.*$', Comment.Single), |
| (r'/\*', Comment.Multiline, 'comment'), |
| # Lexemes: |
| # Identifiers |
| (r'\bimport\b', Keyword.Reserved, 'import'), |
| (r'\bmodule\b', Keyword.Reserved, 'module'), |
| (r'\berror\b', Name.Exception), |
| (r'\b(%s)(?!\')\b' % '|'.join(reserved), Keyword.Reserved), |
| (r'^[_a-z][\w\']*', Name.Function), |
| (r"'?[_a-z][\w']*", Name), |
| (r"('')?[A-Z][\w\']*", Keyword.Type), |
| # Operators |
| (r'\\(?![:!#$%&*+.\\/<=>?@^|~-]+)', Name.Function), # lambda operator |
| (r'(<-|::|->|=>|=)(?![:!#$%&*+.\\/<=>?@^|~-]+)', Operator.Word), # specials |
| (r':[:!#$%&*+.\\/<=>?@^|~-]*', Keyword.Type), # Constructor operators |
| (r'[:!#$%&*+.\\/<=>?@^|~-]+', Operator), # Other operators |
| # Numbers |
| (r'\d+[eE][+-]?\d+', Number.Float), |
| (r'\d+\.\d+([eE][+-]?\d+)?', Number.Float), |
| (r'0[oO][0-7]+', Number.Oct), |
| (r'0[xX][\da-fA-F]+', Number.Hex), |
| (r'\d+', Number.Integer), |
| # Character/String Literals |
| (r"'", String.Char, 'character'), |
| (r'"', String, 'string'), |
| # Special |
| (r'\[\]', Keyword.Type), |
| (r'\(\)', Name.Builtin), |
| (r'[][(),;`{}]', Punctuation), |
| ], |
| 'import': [ |
| # Import statements |
| (r'\s+', Whitespace), |
| (r'"', String, 'string'), |
| # after "funclist" state |
| (r'\)', Punctuation, '#pop'), |
| (r'qualified\b', Keyword), |
| # import X as Y |
| (r'([A-Z][\w.]*)(\s+)(as)(\s+)([A-Z][\w.]*)', |
| bygroups(Name.Namespace, Whitespace, Keyword, Whitespace, Name), '#pop'), |
| # import X hiding (functions) |
| (r'([A-Z][\w.]*)(\s+)(hiding)(\s+)(\()', |
| bygroups(Name.Namespace, Whitespace, Keyword, Whitespace, Punctuation), 'funclist'), |
| # import X (functions) |
| (r'([A-Z][\w.]*)(\s+)(\()', |
| bygroups(Name.Namespace, Whitespace, Punctuation), 'funclist'), |
| # import X |
| (r'[\w.]+', Name.Namespace, '#pop'), |
| ], |
| 'module': [ |
| (r'\s+', Whitespace), |
| (r'([A-Z][\w.]*)(\s+)(\()', |
| bygroups(Name.Namespace, Whitespace, Punctuation), 'funclist'), |
| (r'[A-Z][\w.]*', Name.Namespace, '#pop'), |
| ], |
| 'funclist': [ |
| (r'\s+', Whitespace), |
| (r'[A-Z]\w*', Keyword.Type), |
| (r'(_[\w\']+|[a-z][\w\']*)', Name.Function), |
| # TODO: these don't match the comments in docs, remove. |
| # (r'--(?![!#$%&*+./<=>?@^|_~:\\]).*?$', Comment.Single), |
| # (r'{-', Comment.Multiline, 'comment'), |
| (r',', Punctuation), |
| (r'[:!#$%&*+.\\/<=>?@^|~-]+', Operator), |
| # (HACK, but it makes sense to push two instances, believe me) |
| (r'\(', Punctuation, ('funclist', 'funclist')), |
| (r'\)', Punctuation, '#pop:2'), |
| ], |
| 'comment': [ |
| # Multiline Comments |
| (r'[^/*]+', Comment.Multiline), |
| (r'/\*', Comment.Multiline, '#push'), |
| (r'\*/', Comment.Multiline, '#pop'), |
| (r'[*/]', Comment.Multiline), |
| ], |
| 'character': [ |
| # Allows multi-chars, incorrectly. |
| (r"[^\\']'", String.Char, '#pop'), |
| (r"\\", String.Escape, 'escape'), |
| ("'", String.Char, '#pop'), |
| ], |
| 'string': [ |
| (r'[^\\"]+', String), |
| (r"\\", String.Escape, 'escape'), |
| ('"', String, '#pop'), |
| ], |
| 'escape': [ |
| (r'[abfnrtv"\'&\\]', String.Escape, '#pop'), |
| (r'\^[][A-Z@^_]', String.Escape, '#pop'), |
| ('|'.join(ascii), String.Escape, '#pop'), |
| (r'o[0-7]+', String.Escape, '#pop'), |
| (r'x[\da-fA-F]+', String.Escape, '#pop'), |
| (r'\d+', String.Escape, '#pop'), |
| (r'(\s+)(\\)', bygroups(Whitespace, String.Escape), '#pop'), |
| ], |
| } |
| |
| EXTRA_KEYWORDS = {'join', 'split', 'reverse', 'transpose', 'width', |
| 'length', 'tail', '<<', '>>', '<<<', '>>>', 'const', |
| 'reg', 'par', 'seq', 'ASSERT', 'undefined', 'error', |
| 'trace'} |
| |
| def get_tokens_unprocessed(self, text): |
| stack = ['root'] |
| for index, token, value in \ |
| RegexLexer.get_tokens_unprocessed(self, text, stack): |
| if token is Name and value in self.EXTRA_KEYWORDS: |
| yield index, Name.Builtin, value |
| else: |
| yield index, token, value |
| |
| |
| class LiterateLexer(Lexer): |
| """ |
| Base class for lexers of literate file formats based on LaTeX or Bird-style |
| (prefixing each code line with ">"). |
| |
| Additional options accepted: |
| |
| `litstyle` |
| If given, must be ``"bird"`` or ``"latex"``. If not given, the style |
| is autodetected: if the first non-whitespace character in the source |
| is a backslash or percent character, LaTeX is assumed, else Bird. |
| """ |
| |
| bird_re = re.compile(r'(>[ \t]*)(.*\n)') |
| |
| def __init__(self, baselexer, **options): |
| self.baselexer = baselexer |
| Lexer.__init__(self, **options) |
| |
| def get_tokens_unprocessed(self, text): |
| style = self.options.get('litstyle') |
| if style is None: |
| style = (text.lstrip()[0:1] in '%\\') and 'latex' or 'bird' |
| |
| code = '' |
| insertions = [] |
| if style == 'bird': |
| # bird-style |
| for match in line_re.finditer(text): |
| line = match.group() |
| m = self.bird_re.match(line) |
| if m: |
| insertions.append((len(code), |
| [(0, Comment.Special, m.group(1))])) |
| code += m.group(2) |
| else: |
| insertions.append((len(code), [(0, Text, line)])) |
| else: |
| # latex-style |
| from pygments.lexers.markup import TexLexer |
| lxlexer = TexLexer(**self.options) |
| codelines = 0 |
| latex = '' |
| for match in line_re.finditer(text): |
| line = match.group() |
| if codelines: |
| if line.lstrip().startswith('\\end{code}'): |
| codelines = 0 |
| latex += line |
| else: |
| code += line |
| elif line.lstrip().startswith('\\begin{code}'): |
| codelines = 1 |
| latex += line |
| insertions.append((len(code), |
| list(lxlexer.get_tokens_unprocessed(latex)))) |
| latex = '' |
| else: |
| latex += line |
| insertions.append((len(code), |
| list(lxlexer.get_tokens_unprocessed(latex)))) |
| yield from do_insertions(insertions, self.baselexer.get_tokens_unprocessed(code)) |
| |
| |
| class LiterateHaskellLexer(LiterateLexer): |
| """ |
| For Literate Haskell (Bird-style or LaTeX) source. |
| |
| Additional options accepted: |
| |
| `litstyle` |
| If given, must be ``"bird"`` or ``"latex"``. If not given, the style |
| is autodetected: if the first non-whitespace character in the source |
| is a backslash or percent character, LaTeX is assumed, else Bird. |
| |
| .. versionadded:: 0.9 |
| """ |
| name = 'Literate Haskell' |
| aliases = ['literate-haskell', 'lhaskell', 'lhs'] |
| filenames = ['*.lhs'] |
| mimetypes = ['text/x-literate-haskell'] |
| |
| def __init__(self, **options): |
| hslexer = HaskellLexer(**options) |
| LiterateLexer.__init__(self, hslexer, **options) |
| |
| |
| class LiterateIdrisLexer(LiterateLexer): |
| """ |
| For Literate Idris (Bird-style or LaTeX) source. |
| |
| Additional options accepted: |
| |
| `litstyle` |
| If given, must be ``"bird"`` or ``"latex"``. If not given, the style |
| is autodetected: if the first non-whitespace character in the source |
| is a backslash or percent character, LaTeX is assumed, else Bird. |
| |
| .. versionadded:: 2.0 |
| """ |
| name = 'Literate Idris' |
| aliases = ['literate-idris', 'lidris', 'lidr'] |
| filenames = ['*.lidr'] |
| mimetypes = ['text/x-literate-idris'] |
| |
| def __init__(self, **options): |
| hslexer = IdrisLexer(**options) |
| LiterateLexer.__init__(self, hslexer, **options) |
| |
| |
| class LiterateAgdaLexer(LiterateLexer): |
| """ |
| For Literate Agda source. |
| |
| Additional options accepted: |
| |
| `litstyle` |
| If given, must be ``"bird"`` or ``"latex"``. If not given, the style |
| is autodetected: if the first non-whitespace character in the source |
| is a backslash or percent character, LaTeX is assumed, else Bird. |
| |
| .. versionadded:: 2.0 |
| """ |
| name = 'Literate Agda' |
| aliases = ['literate-agda', 'lagda'] |
| filenames = ['*.lagda'] |
| mimetypes = ['text/x-literate-agda'] |
| |
| def __init__(self, **options): |
| agdalexer = AgdaLexer(**options) |
| LiterateLexer.__init__(self, agdalexer, litstyle='latex', **options) |
| |
| |
| class LiterateCryptolLexer(LiterateLexer): |
| """ |
| For Literate Cryptol (Bird-style or LaTeX) source. |
| |
| Additional options accepted: |
| |
| `litstyle` |
| If given, must be ``"bird"`` or ``"latex"``. If not given, the style |
| is autodetected: if the first non-whitespace character in the source |
| is a backslash or percent character, LaTeX is assumed, else Bird. |
| |
| .. versionadded:: 2.0 |
| """ |
| name = 'Literate Cryptol' |
| aliases = ['literate-cryptol', 'lcryptol', 'lcry'] |
| filenames = ['*.lcry'] |
| mimetypes = ['text/x-literate-cryptol'] |
| |
| def __init__(self, **options): |
| crylexer = CryptolLexer(**options) |
| LiterateLexer.__init__(self, crylexer, **options) |
| |
| |
| class KokaLexer(RegexLexer): |
| """ |
| Lexer for the Koka language. |
| |
| .. versionadded:: 1.6 |
| """ |
| |
| name = 'Koka' |
| url = 'https://koka-lang.github.io/koka/doc/index.html' |
| aliases = ['koka'] |
| filenames = ['*.kk', '*.kki'] |
| mimetypes = ['text/x-koka'] |
| |
| keywords = [ |
| 'infix', 'infixr', 'infixl', |
| 'type', 'cotype', 'rectype', 'alias', |
| 'struct', 'con', |
| 'fun', 'function', 'val', 'var', |
| 'external', |
| 'if', 'then', 'else', 'elif', 'return', 'match', |
| 'private', 'public', 'private', |
| 'module', 'import', 'as', |
| 'include', 'inline', |
| 'rec', |
| 'try', 'yield', 'enum', |
| 'interface', 'instance', |
| ] |
| |
| # keywords that are followed by a type |
| typeStartKeywords = [ |
| 'type', 'cotype', 'rectype', 'alias', 'struct', 'enum', |
| ] |
| |
| # keywords valid in a type |
| typekeywords = [ |
| 'forall', 'exists', 'some', 'with', |
| ] |
| |
| # builtin names and special names |
| builtin = [ |
| 'for', 'while', 'repeat', |
| 'foreach', 'foreach-indexed', |
| 'error', 'catch', 'finally', |
| 'cs', 'js', 'file', 'ref', 'assigned', |
| ] |
| |
| # symbols that can be in an operator |
| symbols = r'[$%&*+@!/\\^~=.:\-?|<>]+' |
| |
| # symbol boundary: an operator keyword should not be followed by any of these |
| sboundary = '(?!' + symbols + ')' |
| |
| # name boundary: a keyword should not be followed by any of these |
| boundary = r'(?![\w/])' |
| |
| # koka token abstractions |
| tokenType = Name.Attribute |
| tokenTypeDef = Name.Class |
| tokenConstructor = Generic.Emph |
| |
| # main lexer |
| tokens = { |
| 'root': [ |
| include('whitespace'), |
| |
| # go into type mode |
| (r'::?' + sboundary, tokenType, 'type'), |
| (r'(alias)(\s+)([a-z]\w*)?', bygroups(Keyword, Whitespace, tokenTypeDef), |
| 'alias-type'), |
| (r'(struct)(\s+)([a-z]\w*)?', bygroups(Keyword, Whitespace, tokenTypeDef), |
| 'struct-type'), |
| ((r'(%s)' % '|'.join(typeStartKeywords)) + |
| r'(\s+)([a-z]\w*)?', bygroups(Keyword, Whitespace, tokenTypeDef), |
| 'type'), |
| |
| # special sequences of tokens (we use ?: for non-capturing group as |
| # required by 'bygroups') |
| (r'(module)(\s+)(interface(?=\s))?(\s+)?((?:[a-z]\w*/)*[a-z]\w*)', |
| bygroups(Keyword, Whitespace, Keyword, Whitespace, Name.Namespace)), |
| (r'(import)(\s+)((?:[a-z]\w*/)*[a-z]\w*)' |
| r'(?:(\s*)(=)(\s*)(qualified)?(\s*)' |
| r'((?:[a-z]\w*/)*[a-z]\w*))?', |
| bygroups(Keyword, Whitespace, Name.Namespace, Whitespace, Keyword, Whitespace, |
| Keyword, Whitespace, Name.Namespace)), |
| |
| (r'^(public|private)?(\s+)?(function|fun|val)' |
| r'(\s+)([a-z]\w*|\((?:' + symbols + r'|/)\))', |
| bygroups(Keyword, Whitespace, Keyword, Whitespace, Name.Function)), |
| (r'^(?:(public|private)(?=\s+external))?((?<!^)\s+)?(external)(\s+)(inline(?=\s))?(\s+)?' |
| r'([a-z]\w*|\((?:' + symbols + r'|/)\))', |
| bygroups(Keyword, Whitespace, Keyword, Whitespace, Keyword, Whitespace, Name.Function)), |
| |
| # keywords |
| (r'(%s)' % '|'.join(typekeywords) + boundary, Keyword.Type), |
| (r'(%s)' % '|'.join(keywords) + boundary, Keyword), |
| (r'(%s)' % '|'.join(builtin) + boundary, Keyword.Pseudo), |
| (r'::?|:=|\->|[=.]' + sboundary, Keyword), |
| |
| # names |
| (r'((?:[a-z]\w*/)*)([A-Z]\w*)', |
| bygroups(Name.Namespace, tokenConstructor)), |
| (r'((?:[a-z]\w*/)*)([a-z]\w*)', bygroups(Name.Namespace, Name)), |
| (r'((?:[a-z]\w*/)*)(\((?:' + symbols + r'|/)\))', |
| bygroups(Name.Namespace, Name)), |
| (r'_\w*', Name.Variable), |
| |
| # literal string |
| (r'@"', String.Double, 'litstring'), |
| |
| # operators |
| (symbols + "|/(?![*/])", Operator), |
| (r'`', Operator), |
| (r'[{}()\[\];,]', Punctuation), |
| |
| # literals. No check for literal characters with len > 1 |
| (r'[0-9]+\.[0-9]+([eE][\-+]?[0-9]+)?', Number.Float), |
| (r'0[xX][0-9a-fA-F]+', Number.Hex), |
| (r'[0-9]+', Number.Integer), |
| |
| (r"'", String.Char, 'char'), |
| (r'"', String.Double, 'string'), |
| ], |
| |
| # type started by alias |
| 'alias-type': [ |
| (r'=', Keyword), |
| include('type') |
| ], |
| |
| # type started by struct |
| 'struct-type': [ |
| (r'(?=\((?!,*\)))', Punctuation, '#pop'), |
| include('type') |
| ], |
| |
| # type started by colon |
| 'type': [ |
| (r'[(\[<]', tokenType, 'type-nested'), |
| include('type-content') |
| ], |
| |
| # type nested in brackets: can contain parameters, comma etc. |
| 'type-nested': [ |
| (r'[)\]>]', tokenType, '#pop'), |
| (r'[(\[<]', tokenType, 'type-nested'), |
| (r',', tokenType), |
| (r'([a-z]\w*)(\s*)(:)(?!:)', |
| bygroups(Name, Whitespace, tokenType)), # parameter name |
| include('type-content') |
| ], |
| |
| # shared contents of a type |
| 'type-content': [ |
| include('whitespace'), |
| |
| # keywords |
| (r'(%s)' % '|'.join(typekeywords) + boundary, Keyword), |
| (r'(?=((%s)' % '|'.join(keywords) + boundary + '))', |
| Keyword, '#pop'), # need to match because names overlap... |
| |
| # kinds |
| (r'[EPHVX]' + boundary, tokenType), |
| |
| # type names |
| (r'[a-z][0-9]*(?![\w/])', tokenType), |
| (r'_\w*', tokenType.Variable), # Generic.Emph |
| (r'((?:[a-z]\w*/)*)([A-Z]\w*)', |
| bygroups(Name.Namespace, tokenType)), |
| (r'((?:[a-z]\w*/)*)([a-z]\w+)', |
| bygroups(Name.Namespace, tokenType)), |
| |
| # type keyword operators |
| (r'::|->|[.:|]', tokenType), |
| |
| # catchall |
| default('#pop') |
| ], |
| |
| # comments and literals |
| 'whitespace': [ |
| (r'(\n\s*)(#.*)$', bygroups(Whitespace, Comment.Preproc)), |
| (r'\s+', Whitespace), |
| (r'/\*', Comment.Multiline, 'comment'), |
| (r'//.*$', Comment.Single) |
| ], |
| 'comment': [ |
| (r'[^/*]+', Comment.Multiline), |
| (r'/\*', Comment.Multiline, '#push'), |
| (r'\*/', Comment.Multiline, '#pop'), |
| (r'[*/]', Comment.Multiline), |
| ], |
| 'litstring': [ |
| (r'[^"]+', String.Double), |
| (r'""', String.Escape), |
| (r'"', String.Double, '#pop'), |
| ], |
| 'string': [ |
| (r'[^\\"\n]+', String.Double), |
| include('escape-sequence'), |
| (r'["\n]', String.Double, '#pop'), |
| ], |
| 'char': [ |
| (r'[^\\\'\n]+', String.Char), |
| include('escape-sequence'), |
| (r'[\'\n]', String.Char, '#pop'), |
| ], |
| 'escape-sequence': [ |
| (r'\\[nrt\\"\']', String.Escape), |
| (r'\\x[0-9a-fA-F]{2}', String.Escape), |
| (r'\\u[0-9a-fA-F]{4}', String.Escape), |
| # Yes, \U literals are 6 hex digits. |
| (r'\\U[0-9a-fA-F]{6}', String.Escape) |
| ] |
| } |