diff options
author | Mark Doffman <mark.doffman@codethink.co.uk> | 2014-03-27 20:50:21 +0000 |
---|---|---|
committer | Mark Doffman <mark.doffman@codethink.co.uk> | 2014-03-27 20:50:21 +0000 |
commit | 68ff94340891f1ae4ea24546acdbbc39c4dcbcd0 (patch) | |
tree | 46f02cba671bcb321482c7961acd91aeee57ced5 /giscanner/mallardwriter.py | |
parent | 19da3f81593614198206c45527f973a22cdd621e (diff) | |
parent | 89e84d06dffbc732bac26a105244b7270c42e3ec (diff) | |
download | gobject-introspection-68ff94340891f1ae4ea24546acdbbc39c4dcbcd0.tar.gz |
Merge tag 'GOBJECT_INTROSPECTION_1_39_90' into baserock/markdoffman/1_39_90-mergebaserock/markdoffman/1_39_90-merge
Tag 1_39_90
Conflicts:
autogen.sh
configure.ac
Diffstat (limited to 'giscanner/mallardwriter.py')
-rw-r--r-- | giscanner/mallardwriter.py | 392 |
1 files changed, 0 insertions, 392 deletions
diff --git a/giscanner/mallardwriter.py b/giscanner/mallardwriter.py deleted file mode 100644 index 9c833843..00000000 --- a/giscanner/mallardwriter.py +++ /dev/null @@ -1,392 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python -*- -# GObject-Introspection - a framework for introspecting GObject libraries -# Copyright (C) 2010 Zach Goldberg -# Copyright (C) 2011 Johan Dahlin -# Copyright (C) 2011 Shaun McCance -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. -# - -import os -import re -import tempfile - -from xml.sax import saxutils -from mako.template import Template - -from . import ast -from .utils import to_underscores - -def make_page_id(namespace, node): - if isinstance(node, ast.Namespace): - return 'index' - elif isinstance(node, (ast.Class, ast.Interface)): - return '%s.%s' % (namespace.name, node.name) - elif isinstance(node, ast.Record): - return '%s.%s' % (namespace.name, node.name) - elif isinstance(node, ast.Function): - if node.parent is not None: - return '%s.%s.%s' % (namespace.name, node.parent.name, node.name) - else: - return '%s.%s' % (namespace.name, node.name) - elif isinstance(node, ast.Enum): - return '%s.%s' % (namespace.name, node.name) - elif isinstance(node, ast.Property) and node.parent is not None: - return '%s.%s-%s' % (namespace.name, node.parent.name, node.name) - elif isinstance(node, ast.Signal) and node.parent is not None: - return '%s.%s-%s' % (namespace.name, node.parent.name, node.name) - elif isinstance(node, ast.VFunction) and node.parent is not None: - return '%s.%s-%s' % (namespace.name, node.parent.name, node.name) - else: - return '%s.%s' % (namespace.name, node.name) - -def make_template_name(node, language): - if isinstance(node, ast.Namespace): - node_kind = 'namespace' - elif isinstance(node, (ast.Class, ast.Interface)): - node_kind = 'class' - elif isinstance(node, ast.Record): - node_kind = 'record' - elif isinstance(node, ast.Function): - node_kind = 'function' - elif isinstance(node, ast.Enum): - node_kind = 'enum' - elif isinstance(node, ast.Property) and node.parent is not None: - node_kind = 'property' - elif isinstance(node, ast.Signal) and node.parent is not None: - node_kind = 'signal' - elif isinstance(node, ast.VFunction) and node.parent is not None: - node_kind = 'vfunc' - else: - node_kind = 'default' - - return 'mallard-%s-%s.tmpl' % (language, node_kind) - -class TemplatedScanner(object): - def __init__(self, specs): - self.specs = self.unmangle_specs(specs) - self.regex = self.make_regex(self.specs) - - def unmangle_specs(self, specs): - mangled = re.compile('<<([a-zA-Z_:]+)>>') - specdict = dict((name.lstrip('!'), spec) for name, spec in specs) - - def unmangle(spec, name=None): - def replace_func(match): - child_spec_name = match.group(1) - - if ':' in child_spec_name: - pattern_name, child_spec_name = child_spec_name.split(':', 1) - else: - pattern_name = None - - child_spec = specdict[child_spec_name] - # Force all child specs of this one to be unnamed - unmangled = unmangle(child_spec, None) - if pattern_name and name: - return '(?P<%s_%s>%s)' % (name, pattern_name, unmangled) - else: - return unmangled - - return mangled.sub(replace_func, spec) - - return [(name, unmangle(spec, name)) for name, spec in specs] - - def make_regex(self, specs): - regex = '|'.join('(?P<%s>%s)' % (name, spec) for name, spec in specs - if not name.startswith('!')) - return re.compile(regex) - - def get_properties(self, name, match): - groupdict = match.groupdict() - properties = {name: groupdict.pop(name)} - name = name + "_" - for group, value in groupdict.iteritems(): - if group.startswith(name): - key = group[len(name):] - properties[key] = value - return properties - - def scan(self, text): - pos = 0 - while True: - match = self.regex.search(text, pos) - if match is None: - break - - start = match.start() - if start > pos: - yield ('other', text[pos:start], None) - - pos = match.end() - name = match.lastgroup - yield (name, match.group(0), self.get_properties(name, match)) - - if pos < len(text): - yield ('other', text[pos:], None) - -class DocstringScanner(TemplatedScanner): - def __init__(self): - specs = [ - ('!alpha', r'[a-zA-Z0-9_]+'), - ('!alpha_dash', r'[a-zA-Z0-9_-]+'), - ('property', r'#<<type_name:alpha>>:(<<property_name:alpha_dash>>)'), - ('signal', r'#<<type_name:alpha>>::(<<signal_name:alpha_dash>>)'), - ('type_name', r'#(<<type_name:alpha>>)'), - ('fundamental', r'%(<<fundamental:alpha>>)'), - ('function_call', r'<<symbol_name:alpha>>\(\)'), - ] - - super(DocstringScanner, self).__init__(specs) - -class MallardFormatter(object): - def __init__(self, transformer): - self._transformer = transformer - self._scanner = DocstringScanner() - - def escape(self, text): - return saxutils.escape(text) - - def format(self, doc): - if doc is None: - return '' - - result = '' - for para in doc.split('\n\n'): - result += '<p>' - result += self.format_inline(para) - result += '</p>' - return result - - def _process_other(self, namespace, match, props): - return self.escape(match) - - def _find_thing(self, list_, name): - for item in list_: - if item.name == name: - return item - raise KeyError("Could not find %s" % (name, )) - - def _process_property(self, namespace, match, props): - type_node = namespace.get_by_ctype(props['type_name']) - if type_node is None: - return match - - try: - node = self._find_thing(type_node.properties, props['property_name']) - except (AttributeError, KeyError), e: - return match - - xref_name = "%s.%s:%s" % (namespace.name, type_node.name, node.name) - return '<link xref="%s">%s</link>' % (make_page_id(namespace, node), xref_name) - - def _process_signal(self, namespace, match, props): - type_node = namespace.get_by_ctype(props['type_name']) - if type_node is None: - return match - - try: - node = self._find_thing(type_node.signals, props['signal_name']) - except (AttributeError, KeyError), e: - return match - - xref_name = "%s.%s::%s" % (namespace.name, type_node.name, node.name) - return '<link xref="%s">%s</link>' % (make_page_id(namespace, node), xref_name) - - def _process_type_name(self, namespace, match, props): - node = namespace.get_by_ctype(props['type_name']) - if node is None: - return match - xref_name = "%s.%s" % (namespace.name, node.name) - return '<link xref="%s">%s</link>' % (make_page_id(namespace, node), xref_name) - - def _process_function_call(self, namespace, match, props): - node = namespace.get_by_symbol(props['symbol_name']) - if node is None: - return match - - return '<link xref="%s">%s</link>' % (make_page_id(namespace, node), - self.format_function_name(node)) - - def _process_fundamental(self, namespace, match, props): - return self.fundamentals.get(props['fundamental'], match) - - def _process_token(self, tok): - namespace = self._transformer.namespace - - kind, match, props = tok - - dispatch = { - 'other': self._process_other, - 'property': self._process_property, - 'signal': self._process_signal, - 'type_name': self._process_type_name, - 'function_call': self._process_function_call, - 'fundamental': self._process_fundamental, - } - - return dispatch[kind](namespace, match, props) - - def format_inline(self, para): - tokens = self._scanner.scan(para) - words = [self._process_token(tok) for tok in tokens] - return ''.join(words) - - def format_function_name(self, func): - raise NotImplementedError - - def format_type(self, type_): - raise NotImplementedError - - def format_property_flags(self, property_): - flags = [] - if property_.readable: - flags.append("Read") - if property_.writable: - flags.append("Write") - if property_.construct: - flags.append("Construct") - if property_.construct_only: - flags.append("Construct Only") - - return " / ".join(flags) - - def to_underscores(self, string): - return to_underscores(string) - - def get_class_hierarchy(self, node): - parent_chain = [node] - - while node.parent: - node = self._transformer.lookup_giname(str(node.parent)) - parent_chain.append(node) - - parent_chain.reverse() - return parent_chain - -class MallardFormatterC(MallardFormatter): - language = "C" - - fundamentals = { - "TRUE": "TRUE", - "FALSE": "FALSE", - "NULL": "NULL", - } - - def format_type(self, type_): - if isinstance(type_, ast.Array): - return self.format_type(type_.element_type) + '*' - elif type_.ctype is not None: - return type_.ctype - else: - return type_.target_fundamental - - def format_function_name(self, func): - return func.symbol - -class MallardFormatterPython(MallardFormatter): - language = "Python" - - fundamentals = { - "TRUE": "True", - "FALSE": "False", - "NULL": "None", - } - - def format_type(self, type_): - if isinstance(type_, ast.Array): - return '[' + self.format_type(type_.element_type) + ']' - elif isinstance(type_, ast.Map): - return '{%s: %s}' % (self.format_type(type_.key_type), - self.format_type(type_.value_type)) - elif type_.target_giname is not None: - return type_.target_giname - else: - return type_.target_fundamental - - def format_function_name(self, func): - if func.parent is not None: - return "%s.%s" % (func.parent.name, func.name) - else: - return func.name - -LANGUAGES = { - "c": MallardFormatterC, - "python": MallardFormatterPython, -} - -class MallardWriter(object): - def __init__(self, transformer, language): - self._transformer = transformer - - try: - formatter_class = LANGUAGES[language.lower()] - except KeyError: - raise SystemExit("Unsupported language: %s" % (language, )) - - self._formatter = formatter_class(self._transformer) - self._language = self._formatter.language - - def write(self, output): - nodes = [self._transformer.namespace] - for node in self._transformer.namespace.itervalues(): - if isinstance(node, ast.Function) and node.moved_to is not None: - continue - if getattr(node, 'disguised', False): - continue - if isinstance(node, ast.Record) and \ - self._language == 'Python' and \ - node.is_gtype_struct_for is not None: - continue - nodes.append(node) - if isinstance(node, (ast.Class, ast.Interface, ast.Record)): - nodes += getattr(node, 'methods', []) - nodes += getattr(node, 'static_methods', []) - nodes += getattr(node, 'virtual_methods', []) - nodes += getattr(node, 'properties', []) - nodes += getattr(node, 'signals', []) - if self._language == 'C': - nodes += getattr(node, 'constructors', []) - for node in nodes: - self._render_node(node, output) - - def _render_node(self, node, output): - namespace = self._transformer.namespace - - if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ: - top_srcdir = os.environ['UNINSTALLED_INTROSPECTION_SRCDIR'] - template_dir = os.path.join(top_srcdir, 'giscanner') - else: - template_dir = os.path.dirname(__file__) - - template_name = make_template_name(node, self._language) - page_id = make_page_id(namespace, node) - - file_name = os.path.join(template_dir, template_name) - file_name = os.path.abspath(file_name) - template = Template(filename=file_name, output_encoding='utf-8', - module_directory=tempfile.gettempdir()) - result = template.render(namespace=namespace, - node=node, - page_id=page_id, - formatter=self._formatter) - - output_file_name = os.path.join(os.path.abspath(output), - page_id + '.page') - fp = open(output_file_name, 'w') - fp.write(result) - fp.close() |