summaryrefslogtreecommitdiff
path: root/codegen/docextract.py
blob: 6abceece25c351f23f8011b0b53d69bcb4c9e1dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# -*- Mode: Python; py-indent-offset: 4 -*-
'''Simple module for extracting GNOME style doc comments from C
sources, so I can use them for other purposes.'''

import sys, os, string, re

class FunctionDoc:
    def __init__(self):
	self.name = None
	self.params = []
	self.description = ''
	self.ret = ''
    def set_name(self, name):
	self.name = name
    def add_param(self, name, description):
	if name == '...':
	    name = 'Varargs'
	self.params.append((name, description))
    def append_to_last_param(self, extra):
	self.params[-1] = (self.params[-1][0], self.params[-1][1] + extra)
    def append_description(self, extra):
	self.description = self.description + extra
    def append_return(self, extra):
	self.ret = self.ret + extra

    def get_param_description(self, name):
        for param, description in self.params:
            if param == name:
                return description
        else:
            return ''

comment_start_pat = re.compile(r'^\s*/\*\*\s')
comment_end_pat = re.compile(r'^\s*\*+/')
comment_line_lead = re.compile(r'^\s*\*\s*')
funcname_pat = re.compile(r'^(\w+)\s*:?')
return_pat = re.compile(r'^(returns:|return\s+value:|returns\s*)(.*\n?)$',
			re.IGNORECASE)
param_pat = re.compile(r'^@(\S+)\s*:(.*\n?)$')

def parse_file(fp, doc_dict):
    line = fp.readline()
    in_comment_block = 0
    while line:
	if not in_comment_block:
	    if comment_start_pat.match(line):
		in_comment_block = 1
		cur_doc = FunctionDoc()
		in_description = 0
		in_return = 0
	    line = fp.readline()
	    continue
	
	# we are inside a comment block ...
	if comment_end_pat.match(line):
	    if not cur_doc.name:
		sys.stderr.write("no function name found in doc comment\n")
	    else:
		doc_dict[cur_doc.name] = cur_doc
	    in_comment_block = 0
	    line = fp.readline()
	    continue

	# inside a comment block, and not the end of the block ...
	line = comment_line_lead.sub('', line)
	if not line: line = '\n'

	if not cur_doc.name:
	    match = funcname_pat.match(line)
	    if match:
		cur_doc.set_name(match.group(1))
	elif in_return:
	    match = return_pat.match(line)
	    if match:
		# assume the last return statement was really part of the
		# description
		cur_doc.description = cur_doc.description + return_start + \
				      cur_doc.ret
		return_start = match.group(1)
		cur_doc.ret = match.group(2)
	    else:
		cur_doc.append_return(line)
	elif in_description:
	    if line[:12] == 'Description:':
		line = line[12:]
	    match = return_pat.match(line)
	    if match:
		in_return = 1
		return_start = match.group(1)
		cur_doc.append_return(match.group(2))
	    else:
		cur_doc.append_description(line)
	elif line == '\n':
	    # end of parameters
	    in_description = 1
	else:
	    match = param_pat.match(line)
	    if match:
		param = match.group(1)
		desc = match.group(2)
		cur_doc.add_param(param, desc)
	    else:
		# must be continuation
		try:
		    cur_doc.append_to_last_param(line)
		except:
		    sys.stderr.write('something weird while reading param\n')
	line = fp.readline()

def parse_dir(dir, doc_dict):
    for file in os.listdir(dir):
	if file in ('.', '..'): continue
	path = os.path.join(dir, file)
	if os.path.isdir(path):
	    parse_dir(path, doc_dict)
	if len(file) > 2 and file[-2:] == '.c':
	    parse_file(open(path, 'r'), doc_dict)

def extract(dirs):
    doc_dict = {}
    for dir in dirs:
	parse_dir(dir, doc_dict)
    return doc_dict