codekingpro/portable-devtools
114k
1"""2 pygments.lexers.php3 ~~~~~~~~~~~~~~~~~~~4 5 Lexers for PHP and related languages.6 7 :copyright: Copyright 2006-present by the Pygments team, see AUTHORS.8 :license: BSD, see LICENSE for details.9"""10 11import re12 13from pygments.lexer import Lexer, RegexLexer, include, bygroups, default, \14 using, this, words, do_insertions, line_re15from pygments.token import Text, Comment, Operator, Keyword, Name, String, \16 Number, Punctuation, Other, Generic17from pygments.util import get_bool_opt, get_list_opt, shebang_matches18 19__all__ = ['ZephirLexer', 'PsyshConsoleLexer', 'PhpLexer']20 21 22class ZephirLexer(RegexLexer):23 """24 For Zephir language source code.25 26 Zephir is a compiled high level language aimed27 to the creation of C-extensions for PHP.28 """29 30 name = 'Zephir'31 url = 'http://zephir-lang.com/'32 aliases = ['zephir']33 filenames = ['*.zep']34 version_added = '2.0'35 36 zephir_keywords = ['fetch', 'echo', 'isset', 'empty']37 zephir_type = ['bit', 'bits', 'string']38 39 flags = re.DOTALL | re.MULTILINE40 41 tokens = {42 'commentsandwhitespace': [43 (r'\s+', Text),44 (r'//.*?\n', Comment.Single),45 (r'/\*.*?\*/', Comment.Multiline)46 ],47 'slashstartsregex': [48 include('commentsandwhitespace'),49 (r'/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/'50 r'([gim]+\b|\B)', String.Regex, '#pop'),51 (r'/', Operator, '#pop'),52 default('#pop')53 ],54 'badregex': [55 (r'\n', Text, '#pop')56 ],57 'root': [58 (r'^(?=\s|/)', Text, 'slashstartsregex'),59 include('commentsandwhitespace'),60 (r'\+\+|--|~|&&|\?|:|\|\||\\(?=\n)|'61 r'(<<|>>>?|==?|!=?|->|[-<>+*%&|^/])=?', Operator, 'slashstartsregex'),62 (r'[{(\[;,]', Punctuation, 'slashstartsregex'),63 (r'[})\].]', Punctuation),64 (r'(for|in|while|do|break|return|continue|switch|case|default|if|else|loop|'65 r'require|inline|throw|try|catch|finally|new|delete|typeof|instanceof|void|'66 r'namespace|use|extends|this|fetch|isset|unset|echo|fetch|likely|unlikely|'67 r'empty)\b', Keyword, 'slashstartsregex'),68 (r'(var|let|with|function)\b', Keyword.Declaration, 'slashstartsregex'),69 (r'(abstract|boolean|bool|char|class|const|double|enum|export|extends|final|'70 r'native|goto|implements|import|int|string|interface|long|ulong|char|uchar|'71 r'float|unsigned|private|protected|public|short|static|self|throws|reverse|'72 r'transient|volatile|readonly)\b', Keyword.Reserved),73 (r'(true|false|null|undefined)\b', Keyword.Constant),74 (r'(Array|Boolean|Date|_REQUEST|_COOKIE|_SESSION|'75 r'_GET|_POST|_SERVER|this|stdClass|range|count|iterator|'76 r'window)\b', Name.Builtin),77 (r'[$a-zA-Z_][\w\\]*', Name.Other),78 (r'[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?', Number.Float),79 (r'0x[0-9a-fA-F]+', Number.Hex),80 (r'[0-9]+', Number.Integer),81 (r'"(\\\\|\\[^\\]|[^"\\])*"', String.Double),82 (r"'(\\\\|\\[^\\]|[^'\\])*'", String.Single),83 ]84 }85 86 87class PsyshConsoleLexer(Lexer):88 """89 For PsySH console output, such as:90 91 .. sourcecode:: psysh92 93 >>> $greeting = function($name): string {94 ... return "Hello, {$name}";95 ... };96 => Closure($name): string {#2371 …3}97 >>> $greeting('World')98 => "Hello, World"99 """100 name = 'PsySH console session for PHP'101 url = 'https://psysh.org/'102 aliases = ['psysh']103 version_added = '2.7'104 105 def __init__(self, **options):106 options['startinline'] = True107 Lexer.__init__(self, **options)108 109 def get_tokens_unprocessed(self, text):110 phplexer = PhpLexer(**self.options)111 curcode = ''112 insertions = []113 for match in line_re.finditer(text):114 line = match.group()115 if line.startswith('>>> ') or line.startswith('... '):116 insertions.append((len(curcode),117 [(0, Generic.Prompt, line[:4])]))118 curcode += line[4:]119 elif line.rstrip() == '...':120 insertions.append((len(curcode),121 [(0, Generic.Prompt, '...')]))122 curcode += line[3:]123 else:124 if curcode:125 yield from do_insertions(126 insertions, phplexer.get_tokens_unprocessed(curcode))127 curcode = ''128 insertions = []129 yield match.start(), Generic.Output, line130 if curcode:131 yield from do_insertions(insertions,132 phplexer.get_tokens_unprocessed(curcode))133 134 135class PhpLexer(RegexLexer):136 """137 For PHP source code.138 For PHP embedded in HTML, use the `HtmlPhpLexer`.139 140 Additional options accepted:141 142 `startinline`143 If given and ``True`` the lexer starts highlighting with144 php code (i.e.: no starting ``<?php`` required). The default145 is ``False``.146 `funcnamehighlighting`147 If given and ``True``, highlight builtin function names148 (default: ``True``).149 `disabledmodules`150 If given, must be a list of module names whose function names151 should not be highlighted. By default all modules are highlighted152 except the special ``'unknown'`` module that includes functions153 that are known to php but are undocumented.154 155 To get a list of allowed modules have a look into the156 `_php_builtins` module:157 158 .. sourcecode:: pycon159 160 >>> from pygments.lexers._php_builtins import MODULES161 >>> MODULES.keys()162 ['PHP Options/Info', 'Zip', 'dba', ...]163 164 In fact the names of those modules match the module names from165 the php documentation.166 """167 168 name = 'PHP'169 url = 'https://www.php.net/'170 aliases = ['php', 'php3', 'php4', 'php5']171 filenames = ['*.php', '*.php[345]', '*.inc']172 mimetypes = ['text/x-php']173 version_added = ''174 175 # Note that a backslash is included, PHP uses a backslash as a namespace176 # separator.177 _ident_inner = r'(?:[\\_a-z]|[^\x00-\x7f])(?:[\\\w]|[^\x00-\x7f])*'178 # But not inside strings.179 _ident_nons = r'(?:[_a-z]|[^\x00-\x7f])(?:\w|[^\x00-\x7f])*'180 181 flags = re.IGNORECASE | re.DOTALL | re.MULTILINE182 tokens = {183 'root': [184 (r'<\?(php)?', Comment.Preproc, 'php'),185 (r'[^<]+', Other),186 (r'<', Other)187 ],188 'php': [189 (r'\?>', Comment.Preproc, '#pop'),190 (r'(<<<)([\'"]?)(' + _ident_nons + r')(\2\n.*?\n\s*)(\3)(;?)(\n)',191 bygroups(String, String, String.Delimiter, String, String.Delimiter,192 Punctuation, Text)),193 (r'\s+', Text),194 (r'#\[', Punctuation, 'attribute'),195 (r'#.*?\n', Comment.Single),196 (r'//.*?\n', Comment.Single),197 # put the empty comment here, it is otherwise seen as198 # the start of a docstring199 (r'/\*\*/', Comment.Multiline),200 (r'/\*\*.*?\*/', String.Doc),201 (r'/\*.*?\*/', Comment.Multiline),202 (r'(->|::)(\s*)(' + _ident_nons + ')',203 bygroups(Operator, Text, Name.Attribute)),204 (r'[~!%^&*+=|:.<>/@-]+', Operator),205 (r'\?', Operator), # don't add to the charclass above!206 (r'[\[\]{}();,]+', Punctuation),207 (r'(new)(\s+)(class)\b', bygroups(Keyword, Text, Keyword)),208 (r'(class)(\s+)', bygroups(Keyword, Text), 'classname'),209 (r'(function)(\s*)(?=\()', bygroups(Keyword, Text)),210 (r'(function)(\s+)(&?)(\s*)',211 bygroups(Keyword, Text, Operator, Text), 'functionname'),212 (r'(const)(\s+)(' + _ident_inner + ')',213 bygroups(Keyword, Text, Name.Constant)),214 # source: https://www.php.net/manual/en/reserved.keywords.php215 (r'(and|E_PARSE|old_function|E_ERROR|or|as|E_WARNING|parent|'216 r'eval|PHP_OS|break|exit|case|extends|PHP_VERSION|cfunction|'217 r'FALSE|print|for|require|continue|foreach|require_once|'218 r'declare|return|default|static|do|switch|die|stdClass|'219 r'echo|else|TRUE|elseif|var|empty|if|xor|enddeclare|include|'220 r'virtual|endfor|include_once|while|endforeach|global|'221 r'endif|list|endswitch|new|endwhile|not|'222 r'array|E_ALL|NULL|final|php_user_filter|interface|'223 r'implements|public|private|protected|abstract|clone|try|'224 r'catch|throw|this|use|namespace|trait|yield( from)?|'225 r'finally|match|readonly)\b', Keyword),226 (r'(true|false|null)\b', Keyword.Constant),227 include('magicconstants'),228 (r'\$\{', Name.Variable, 'variablevariable'),229 (r'\$+' + _ident_inner, Name.Variable),230 (_ident_inner, Name.Other),231 (r'(\d+\.\d*|\d*\.\d+)(e[+-]?[0-9]+)?', Number.Float),232 (r'\d+e[+-]?[0-9]+', Number.Float),233 (r'0[0-7]+', Number.Oct),234 (r'0x[a-f0-9]+', Number.Hex),235 (r'\d+', Number.Integer),236 (r'0b[01]+', Number.Bin),237 (r"'([^'\\]*(?:\\.[^'\\]*)*)'", String.Single),238 (r'`([^`\\]*(?:\\.[^`\\]*)*)`', String.Backtick),239 (r'"', String.Double, 'string'),240 ],241 'variablevariable': [242 (r'\}', Name.Variable, '#pop'),243 include('php')244 ],245 'magicfuncs': [246 # source: http://php.net/manual/en/language.oop5.magic.php247 (words((248 '__construct', '__destruct', '__call', '__callStatic', '__get', '__set',249 '__isset', '__unset', '__sleep', '__wakeup', '__toString', '__invoke',250 '__set_state', '__clone', '__debugInfo',), suffix=r'\b'),251 Name.Function.Magic),252 ],253 'magicconstants': [254 # source: https://www.php.net/manual/en/language.constants.magic.php255 (words((256 '__LINE__', '__FILE__', '__DIR__', '__FUNCTION__', '__CLASS__',257 '__TRAIT__', '__METHOD__', '__NAMESPACE__', '__PROPERTY__',),258 suffix=r'\b'),259 Name.Constant),260 ],261 'classname': [262 (_ident_inner, Name.Class, '#pop')263 ],264 'functionname': [265 include('magicfuncs'),266 (_ident_inner, Name.Function, '#pop'),267 default('#pop')268 ],269 'string': [270 (r'"', String.Double, '#pop'),271 (r'[^{$"\\]+', String.Double),272 (r'\\([nrt"$\\]|[0-7]{1,3}|x[0-9a-f]{1,2})', String.Escape),273 (r'\$' + _ident_nons + r'(\[\S+?\]|->' + _ident_nons + ')?',274 String.Interpol),275 (r'(\{\$\{)(.*?)(\}\})',276 bygroups(String.Interpol, using(this, _startinline=True),277 String.Interpol)),278 (r'(\{)(\$.*?)(\})',279 bygroups(String.Interpol, using(this, _startinline=True),280 String.Interpol)),281 (r'(\$\{)(\S+)(\})',282 bygroups(String.Interpol, Name.Variable, String.Interpol)),283 (r'[${\\]', String.Double)284 ],285 'attribute': [286 (r'\]', Punctuation, '#pop'),287 (r'\(', Punctuation, 'attributeparams'),288 (_ident_inner, Name.Decorator),289 include('php')290 ],291 'attributeparams': [292 (r'\)', Punctuation, '#pop'),293 include('php')294 ],295 }296 297 def __init__(self, **options):298 self.funcnamehighlighting = get_bool_opt(299 options, 'funcnamehighlighting', True)300 self.disabledmodules = get_list_opt(301 options, 'disabledmodules', ['unknown'])302 self.startinline = get_bool_opt(options, 'startinline', False)303 304 # private option argument for the lexer itself305 if '_startinline' in options:306 self.startinline = options.pop('_startinline')307 308 # collect activated functions in a set309 self._functions = set()310 if self.funcnamehighlighting:311 from pygments.lexers._php_builtins import MODULES312 for key, value in MODULES.items():313 if key not in self.disabledmodules:314 self._functions.update(value)315 RegexLexer.__init__(self, **options)316 317 def get_tokens_unprocessed(self, text):318 stack = ['root']319 if self.startinline:320 stack.append('php')321 for index, token, value in \322 RegexLexer.get_tokens_unprocessed(self, text, stack):323 if token is Name.Other:324 if value in self._functions:325 yield index, Name.Builtin, value326 continue327 yield index, token, value328 329 def analyse_text(text):330 if shebang_matches(text, r'php'):331 return True332 rv = 0.0333 if re.search(r'<\?(?!xml)', text):334 rv += 0.3335 return rv336 