File: Synopsis/Formatters/HTML/Markup/__init__.py
  1#
  2# Copyright (C) 2006 Stefan Seefeld
  3# All rights reserved.
  4# Licensed to the public under the terms of the GNU LGPL (>= 2),
  5# see the file COPYING for details.
  6#
  7"""Markup formatters."""
  8
  9from Synopsis.Processor import Parametrized, Parameter
 10from Synopsis import ASG
 11from Synopsis.QualifiedName import *
 12from Synopsis.Formatters.HTML.Tags import escape
 13import re
 14
 15class Struct:
 16
 17    def __init__(self, summary = '', details = ''):
 18        self.summary = summary
 19        self.details = details
 20
 21
 22class Formatter(Parametrized):
 23    """Interface class that takes a 'doc' annotation and formats its
 24    text. Markup-specific subclasses should provide appropriate format methods."""
 25
 26    def init(self, processor):
 27
 28        self.processor = processor
 29
 30    def format(self, decl, view):
 31        """Format the declaration's documentation.
 32        @param view the View to use for references and determining the correct
 33        relative filename.
 34        @param decl the declaration
 35        @returns Struct containing summary / details pair.
 36        """
 37
 38        doc = decl.annotations.get('doc')
 39        text = doc and escape(doc.text) or ''
 40        m = re.match(r'(\s*[\w\W]*?\.)(\s|$)', text)
 41        summary = m and m.group(1) or ''
 42        return Struct(summary, text)
 43
 44    def lookup_symbol(self, symbol, scope):
 45        """Given a symbol and a scope, returns an URL.
 46        Various methods are tried to resolve the symbol. First the
 47        parameters are taken off, then we try to split the symbol using '.' or
 48        '::'. The params are added back, and then we try to match this scoped
 49        name against the current scope. If that fails, then we recursively try
 50        enclosing scopes.
 51        """
 52
 53        # Remove params
 54        index = symbol.find('(')
 55        if index >= 0:
 56            params = symbol[index:]
 57            symbol = symbol[:index]
 58        else:
 59            params = ''
 60        if '.' in symbol:
 61            symbol = QualifiedPythonName(symbol.split('.'))
 62        else:
 63            symbol = QualifiedCxxName(symbol.split('::'))
 64        # Add params back
 65        symbol = symbol[:-1] + (symbol[-1] + params,)
 66        # Find in all scopes
 67        while 1:
 68            entry = self._lookup_symbol_in(symbol, scope)
 69            if entry:
 70                return entry.link
 71            if len(scope) == 0: break
 72            scope = scope[:-1]
 73        # Not found
 74        return None
 75
 76
 77    def _lookup_symbol_in(self, symbol, scope):
 78
 79        paren = symbol[-1].find('(')
 80        if paren != -1:
 81            return self._find_method_entry(symbol[-1], scope + symbol[:-1])
 82        else:
 83            return self.processor.toc.lookup(scope + symbol)
 84
 85
 86    def _find_method_entry(self, name, scope):
 87
 88        try:
 89            scope = self.processor.ir.asg.types[scope]
 90        except KeyError:
 91            return None
 92        if not isinstance(scope, ASG.DeclaredTypeId):
 93            return None
 94        scope = scope.declaration
 95        if not isinstance(scope, ASG.Scope):
 96            return None
 97        # For now disregard parameters during lookup.
 98        name = name[:name.find('(')]
 99        for d in scope.declarations:
100            if isinstance(d, ASG.Function):
101                if d.real_name[-1] == name:
102                    return self.processor.toc.lookup(d.name)
103        return None
104