2 # -*- coding: utf-8 -*-
4 # Author: Enrico Tröger
5 # License: GPL v2 or later
7 # This script downloads the PHP tag definitions in JSON format from
8 # http://doc.php.net/downloads/json/php_manual_en.json.
9 # From those defintions all function tags are extracted and written
10 # to ../data/tags/std.php.tags (relative to the script's location, not $CWD).
12 from json
import loads
13 from os
.path
import dirname
, join
14 from urllib2
import urlopen
18 UPSTREAM_TAG_DEFINITION
= 'http://doc.php.net/downloads/json/php_manual_en.json'
19 PROTOTYPE_RE
= r
'^(?P<return_type>.*) {tag_name}(?P<arg_list>\(.*\))$'
21 # (from src/tagmanager/tm_tag.c:90)
27 # TMTagType (src/tagmanager/tm_tag.h:49)
35 #----------------------------------------------------------------------
36 def normalize_name(name
):
37 """ Replace namespace separator with class separators, as Geany only
38 understands the latter """
39 return name
.replace('\\', '::')
42 #----------------------------------------------------------------------
43 def split_scope(name
):
44 """ Splits the scope from the member, and returns (scope, member).
45 Returned scope is None if the name is not a member """
46 name
= normalize_name(name
)
47 sep_pos
= name
.rfind('::')
51 return name
[:sep_pos
], name
[sep_pos
+2:]
54 #----------------------------------------------------------------------
55 def parse_and_create_php_tags_file():
56 # download upstream definition
57 response
= urlopen(UPSTREAM_TAG_DEFINITION
)
59 html
= response
.read()
64 definitions
= loads(html
)
68 for tag_name
, tag_definition
in definitions
.items():
69 prototype_re
= PROTOTYPE_RE
.format(tag_name
=re
.escape(tag_name
))
70 match
= re
.match(prototype_re
, tag_definition
['prototype'])
72 return_type
= normalize_name(match
.group('return_type'))
73 arg_list
= match
.group('arg_list')
75 scope
, tag_name
= split_scope(tag_name
)
76 if tag_name
[0] == '$':
77 tag_type
= TYPE_MEMBER
if scope
is not None else TYPE_VARIABLE
79 tag_type
= TYPE_METHOD
if scope
is not None else TYPE_FUNCTION
80 tag_list
.append((tag_name
, tag_type
, return_type
, arg_list
, scope
))
81 # Also create a class tag when encountering a __construct()
82 if tag_name
== '__construct' and scope
is not None:
83 scope
, tag_name
= split_scope(scope
)
84 tag_list
.append((tag_name
, TYPE_CLASS
, None, arg_list
, scope
))
87 script_dir
= dirname(__file__
)
88 tags_file_path
= join(script_dir
, '..', 'data', 'tags', 'std.php.tags')
89 with
open(tags_file_path
, 'w') as tags_file
:
90 tags_file
.write('# format=tagmanager\n')
91 for tag_name
, tag_type
, return_type
, arg_list
, scope
in sorted(tag_list
):
92 tag_line
= '{}'.format(tag_name
)
93 for attr
, type in [(tag_type
, TA_TYPE
),
94 (arg_list
, TA_ARGLIST
),
95 (return_type
, TA_VARTYPE
),
98 tag_line
+= '{type:c}{attr}'.format(type=type, attr
=attr
)
100 tags_file
.write(tag_line
+ '\n')
101 print(u
'Created: {} with {} tags'.format(tags_file_path
, len(tag_list
)))
104 if __name__
== '__main__':
105 parse_and_create_php_tags_file()