diff options
author | Zhenyi Zhou <zhouzhen1@gmail.com> | 2017-01-01 19:59:11 +0800 |
---|---|---|
committer | Zhenyi Zhou <zhouzhen1@gmail.com> | 2017-01-01 19:59:11 +0800 |
commit | 0fa23bf835caf6dc01ddb7fde63e01113a7b10af (patch) | |
tree | 714cac034db2edb2e0691504a2cc832732bb0e21 | |
parent | 56e75b33d66738b072f9f5525f3af4a8ba863d8b (diff) | |
download | pygments-0fa23bf835caf6dc01ddb7fde63e01113a7b10af.tar.gz |
Fix Perl5 lexer for namespaces/modules. Also see https://github.com/EntropyOrg/p5-Devel-IPerl/issues/25
-rw-r--r-- | pygments/lexers/perl.py | 24 | ||||
-rw-r--r-- | tests/test_perllexer.py | 22 |
2 files changed, 35 insertions, 11 deletions
diff --git a/pygments/lexers/perl.py b/pygments/lexers/perl.py index 8df3c810..8aa53756 100644 --- a/pygments/lexers/perl.py +++ b/pygments/lexers/perl.py @@ -52,7 +52,7 @@ class PerlLexer(RegexLexer): (words(( 'case', 'continue', 'do', 'else', 'elsif', 'for', 'foreach', 'if', 'last', 'my', 'next', 'our', 'redo', 'reset', 'then', - 'unless', 'until', 'while', 'use', 'print', 'new', 'BEGIN', + 'unless', 'until', 'while', 'print', 'new', 'BEGIN', 'CHECK', 'INIT', 'END', 'return'), suffix=r'\b'), Keyword), (r'(format)(\s+)(\w+)(\s*)(=)(\s*\n)', @@ -94,10 +94,10 @@ class PerlLexer(RegexLexer): 'getservbyport', 'getservent', 'getsockname', 'getsockopt', 'glob', 'gmtime', 'goto', 'grep', 'hex', 'import', 'index', 'int', 'ioctl', 'join', 'keys', 'kill', 'last', 'lc', 'lcfirst', 'length', 'link', 'listen', 'local', 'localtime', 'log', 'lstat', - 'map', 'mkdir', 'msgctl', 'msgget', 'msgrcv', 'msgsnd', 'my', 'next', 'no', 'oct', 'open', - 'opendir', 'ord', 'our', 'pack', 'package', 'pipe', 'pop', 'pos', 'printf', + 'map', 'mkdir', 'msgctl', 'msgget', 'msgrcv', 'msgsnd', 'my', 'next', 'oct', 'open', + 'opendir', 'ord', 'our', 'pack', 'pipe', 'pop', 'pos', 'printf', 'prototype', 'push', 'quotemeta', 'rand', 'read', 'readdir', - 'readline', 'readlink', 'readpipe', 'recv', 'redo', 'ref', 'rename', 'require', + 'readline', 'readlink', 'readpipe', 'recv', 'redo', 'ref', 'rename', 'reverse', 'rewinddir', 'rindex', 'rmdir', 'scalar', 'seek', 'seekdir', 'select', 'semctl', 'semget', 'semop', 'send', 'setgrent', 'sethostent', 'setnetent', 'setpgrp', 'setpriority', 'setprotoent', 'setpwent', 'setservent', @@ -131,8 +131,14 @@ class PerlLexer(RegexLexer): (r'(q|qq|qw|qr|qx)\[', String.Other, 'sb-string'), (r'(q|qq|qw|qr|qx)\<', String.Other, 'lt-string'), (r'(q|qq|qw|qr|qx)([\W_])(.|\n)*?\2', String.Other), - (r'package\s+', Keyword, 'modulename'), - (r'sub\s+', Keyword, 'funcname'), + (r'(package)(\s+)([a-zA-Z_]\w*(?:::[a-zA-Z_]\w*)*)', + bygroups(Keyword, Text, Name.Namespace)), + (r'(use|require|no)(\s+)([a-zA-Z_]\w*(?:::[a-zA-Z_]\w*)*)', + bygroups(Keyword, Text, Name.Namespace)), + (r'(sub)(\s+)', bygroups(Keyword, Text), 'funcname'), + (words(( + 'no', 'package', 'require', 'use'), suffix=r'\b'), + Keyword), (r'(\[\]|\*\*|::|<<|>>|>=|<=>|<=|={3}|!=|=~|' r'!~|&&?|\|\||\.{1,3})', Operator), (r'[-+/*%=<>&^|!\\~]=?', Operator), @@ -152,14 +158,12 @@ class PerlLexer(RegexLexer): (r'[\w:]+', Name.Variable, '#pop'), ], 'name': [ - (r'\w+::', Name.Namespace), + (r'[a-zA-Z_]\w*(::[a-zA-Z_]\w*)*(::)?(?=\s*->)', Name.Namespace, '#pop'), + (r'[a-zA-Z_]\w*(::[a-zA-Z_]\w*)*::', Name.Namespace, '#pop'), (r'[\w:]+', Name, '#pop'), (r'[A-Z_]+(?=\W)', Name.Constant, '#pop'), (r'(?=\W)', Text, '#pop'), ], - 'modulename': [ - (r'[a-zA-Z_]\w*', Name.Namespace, '#pop') - ], 'funcname': [ (r'[a-zA-Z_]\w*[!?]?', Name.Function), (r'\s+', Text), diff --git a/tests/test_perllexer.py b/tests/test_perllexer.py index 26b2d0a7..90741397 100644 --- a/tests/test_perllexer.py +++ b/tests/test_perllexer.py @@ -10,7 +10,7 @@ import time import unittest -from pygments.token import String +from pygments.token import Keyword, Name, String, Text from pygments.lexers.perl import PerlLexer @@ -135,3 +135,23 @@ class RunawayRegexTest(unittest.TestCase): def test_substitution_with_parenthesis(self): self.assert_single_token(r's(aaa)', String.Regex) self.assert_fast_tokenization('s(' + '\\'*999) + + ### Namespaces/modules + + def test_package_statement(self): + self.assert_tokens(['package', ' ', 'Foo'], [Keyword, Text, Name.Namespace]) + self.assert_tokens(['package', ' ', 'Foo::Bar'], [Keyword, Text, Name.Namespace]) + + def test_use_statement(self): + self.assert_tokens(['use', ' ', 'Foo'], [Keyword, Text, Name.Namespace]) + self.assert_tokens(['use', ' ', 'Foo::Bar'], [Keyword, Text, Name.Namespace]) + + def test_no_statement(self): + self.assert_tokens(['no', ' ', 'Foo'], [Keyword, Text, Name.Namespace]) + self.assert_tokens(['no', ' ', 'Foo::Bar'], [Keyword, Text, Name.Namespace]) + + def test_require_statement(self): + self.assert_tokens(['require', ' ', 'Foo'], [Keyword, Text, Name.Namespace]) + self.assert_tokens(['require', ' ', 'Foo::Bar'], [Keyword, Text, Name.Namespace]) + self.assert_tokens(['require', ' ', '"Foo/Bar.pm"'], [Keyword, Text, String]) + |