3 # GObject-Introspection - a framework for introspecting GObject libraries
4 # Copyright (C) 2010 Zach Goldberg
5 # Copyright (C) 2011 Johan Dahlin
6 # Copyright (C) 2011 Shaun McCance
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License
10 # as published by the Free Software Foundation; either version 2
11 # of the License, or (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 from xml.sax import saxutils
29 from mako.template import Template
30 from mako.runtime import supports_caller
33 from .utils import to_underscores
38 class MallardFormatter(object):
39 def __init__(self, transformer):
40 self._transformer = transformer
42 def escape(self, text):
43 return saxutils.escape(text.encode('utf-8')).decode('utf-8')
45 def format(self, doc):
50 for para in doc.split('\n\n'):
52 result += self.format_inline(para)
56 def format_inline(self, para):
60 poss.append((para.find('#'), '#'))
61 poss = [pos for pos in poss if pos[0] >= 0]
62 poss.sort(cmp=lambda x, y: cmp(x[0], y[0]))
64 result += self.escape(para)
65 elif poss[0][1] == '#':
67 result += self.escape(para[:pos])
69 link = re.split('[^a-zA-Z_:-]', rest, maxsplit=1)[0]
70 if link.endswith(':'):
72 namespace = self._transformer.namespace
74 type_name, signal_name = link.split('::')
75 if type_name in namespace.ctypes:
76 type_ = namespace.get_by_ctype(type_name)
77 xref = '%s.%s-%s' % (namespace.name, type_.name, signal_name)
78 xref_name = '%s.%s::%s' % (namespace.name, type_.name, signal_name)
83 type_name, property_name = link.split(':')
84 if type_name in namespace.ctypes:
85 type_ = namespace.get_by_ctype(type_name)
86 xref = '%s.%s-%s' % (namespace.name, type_.name, property_name)
87 xref_name = '%s.%s:%s' % (namespace.name, type_.name, property_name)
91 elif link in namespace.ctypes:
92 type_ = namespace.get_by_ctype(link)
93 xref = '%s.%s' % (namespace.name, type_.name)
98 result += '<link xref="%s">%s</link>' % (xref, xref_name)
99 if len(link) < len(rest):
100 result += self.format_inline(rest[len(link):])
104 def format_type(self, type_):
105 raise NotImplementedError
107 def format_property_flags(self, property_):
109 if property_.readable:
111 if property_.writable:
112 flags.append("Write")
113 if property_.construct:
114 flags.append("Construct")
115 if property_.construct_only:
116 flags.append("Construct Only")
118 return " / ".join(flags)
120 def to_underscores(self, string):
121 return to_underscores(string)
123 def get_class_hierarchy(self, node):
124 parent_chain = [node]
127 node = self._transformer.lookup_giname(str(node.parent))
128 parent_chain.append(node)
130 parent_chain.reverse()
133 class MallardFormatterC(MallardFormatter):
135 def format_type(self, type_):
136 if isinstance(type_, ast.Array):
138 return self.format_type(type_.element_type) + '*'
140 return type_.target_fundamental
141 elif type_.ctype is not None:
144 return type_.target_fundamental
146 class MallardFormatterPython(MallardFormatter):
148 def format_type(self, type_):
149 if isinstance(type_, ast.Array):
150 return '[' + self.format_type(type_.element_type) + ']'
151 elif isinstance(type_, ast.Map):
152 return '{%s: %s}' % (self.format_type(type_.key_type),
153 self.format_type(type_.value_type))
154 elif type_.target_giname is not None:
155 return type_.target_giname
157 return type_.target_fundamental
159 def format(self, doc):
160 doc = MallardFormatter.format(self, doc)
161 doc = doc.replace('%NULL', 'None')
162 doc = doc.replace('%TRUE', 'True')
163 doc = doc.replace('%FALSE', 'False')
166 class MallardWriter(object):
167 def __init__(self, transformer, language):
168 self._transformer = transformer
169 self._language = language
171 if self._language == 'C':
172 self._formatter = MallardFormatterC(self._transformer)
173 elif self._language == 'Python':
174 self._formatter = MallardFormatterPython(self._transformer)
176 raise SystemExit("Unsupported language: %s" % language)
178 def write(self, output):
179 nodes = [self._transformer.namespace]
180 for node in self._transformer.namespace.itervalues():
181 if isinstance(node, ast.Function) and node.moved_to is not None:
183 if getattr(node, 'disguised', False):
185 if isinstance(node, ast.Record) and \
186 self._language == 'Python' and \
187 node.is_gtype_struct_for is not None:
190 if isinstance(node, (ast.Class, ast.Interface, ast.Record)):
191 nodes += getattr(node, 'methods', [])
192 nodes += getattr(node, 'static_methods', [])
193 nodes += getattr(node, 'virtual_methods', [])
194 nodes += getattr(node, 'properties', [])
195 nodes += getattr(node, 'signals', [])
196 if self._language == 'C':
197 nodes += getattr(node, 'constructors', [])
199 self._render_node(node, output)
201 def _render_node(self, node, output):
202 namespace = self._transformer.namespace
203 if isinstance(node, ast.Namespace):
204 template_name = 'mallard-%s-namespace.tmpl' % self._language
206 elif isinstance(node, (ast.Class, ast.Interface)):
207 template_name = 'mallard-%s-class.tmpl' % self._language
208 page_id = '%s.%s' % (namespace.name, node.name)
209 elif isinstance(node, ast.Record):
210 template_name = 'mallard-%s-record.tmpl' % self._language
211 page_id = '%s.%s' % (namespace.name, node.name)
212 elif isinstance(node, ast.Function):
213 template_name = 'mallard-%s-function.tmpl' % self._language
214 if node.parent is not None:
215 page_id = '%s.%s.%s' % (namespace.name, node.parent.name, node.name)
217 page_id = '%s.%s' % (namespace.name, node.name)
218 elif isinstance(node, ast.Enum):
219 template_name = 'mallard-%s-enum.tmpl' % self._language
220 page_id = '%s.%s' % (namespace.name, node.name)
221 elif isinstance(node, ast.Property) and node.parent is not None:
222 template_name = 'mallard-%s-property.tmpl' % self._language
223 page_id = '%s.%s-%s' % (namespace.name, node.parent.name, node.name)
224 elif isinstance(node, ast.Signal) and node.parent is not None:
225 template_name = 'mallard-%s-signal.tmpl' % self._language
226 page_id = '%s.%s-%s' % (namespace.name, node.parent.name, node.name)
227 elif isinstance(node, ast.VFunction) and node.parent is not None:
228 template_name = 'mallard-%s-vfunc.tmpl' % self._language
229 page_id = '%s.%s-%s' % (namespace.name, node.parent.name, node.name)
231 template_name = 'mallard-%s-default.tmpl' % self._language
232 page_id = '%s.%s' % (namespace.name, node.name)
234 if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
235 top_srcdir = os.environ['UNINSTALLED_INTROSPECTION_SRCDIR']
236 template_dir = os.path.join(top_srcdir, 'giscanner')
238 template_dir = os.path.dirname(__file__)
240 file_name = os.path.join(template_dir, template_name)
241 file_name = os.path.abspath(file_name)
242 template = Template(filename=file_name, output_encoding='utf-8',
243 module_directory=tempfile.gettempdir())
244 result = template.render(namespace=namespace,
247 formatter=self._formatter)
249 output_file_name = os.path.join(os.path.abspath(output),
251 fp = open(output_file_name, 'w')