[Synopsis-changes] Synopsis/Synopsis/Synopsis/Formatters/HTML/Comments Javadoc.py,NONE,1.1 Qtdoc.py,NONE,1.1 QuoteHTML.py,NONE,1.1 Section.py,NONE,1.1 __init__.py,NONE,1.1 Formatter.py,1.23,1.24

Stefan Seefeld stefan at synopsis.fresco.org
Thu Dec 4 21:04:30 UTC 2003


Update of /cvs/synopsis/Synopsis/Synopsis/Formatters/HTML/Comments
In directory frida:/tmp/cvs-serv1738/Comments

Modified Files:
	Formatter.py 
Added Files:
	Javadoc.py Qtdoc.py QuoteHTML.py Section.py __init__.py 
Log Message:
put comment formatters into their own package

--- NEW FILE: Javadoc.py ---
# $Id: Javadoc.py,v 1.1 2003/12/04 21:04:28 stefan Exp $
#
# Copyright (C) 2000 Stephen Davies
# Copyright (C) 2000 Stefan Seefeld
# All rights reserved.
# Licensed to the public under the terms of the GNU LGPL (>= 2),
# see the file COPYING for details.
#

from Formatter import Formatter
import re

class Javadoc(Formatter):
   """A formatter that formats comments similar to Javadoc @tags"""

   # @see IDL/Foo.Bar
   _re_see = '@see (([A-Za-z+]+)/)?(([A-Za-z_]+\.?)+)'
   _re_see_line = '^[ \t]*@see[ \t]+(([A-Za-z+]+)/)?(([A-Za-z_]+\.?)+)(\([^)]*\))?([ \t]+(.*))?$'
   _re_param = '^[ \t]*@param[ \t]+(?P<name>(A-Za-z+]+)([ \t]+(?P<desc>.*))?$'

   def __init__(self):
      """Create regex objects for regexps"""

      self.re_see = re.compile(self._re_see)
      self.re_see_line = re.compile(self._re_see_line,re.M)

   def extract(self, regexp, str):
      """Extracts all matches of the regexp from the text. The MatchObjects
      are returned in a list"""

      mo = regexp.search(str)
      ret = []
      while mo:
         ret.append(mo)
         start, end = mo.start(), mo.end()
         str = str[:start] + str[end:]
         mo = regexp.search(str, start)
      return str, ret

   def format(self, page, decl, text):
      """Format any @tags in the text, and any @tags stored by the JavaTags
      CommentProcessor in the Linker stage."""

      if text is None: return text
      see_tags, attr_tags, param_tags, return_tag = [], [], [], None
      tags = decl.comments()[0].tags()
      # Parse each of the tags
      for tag in tags:
         name, rest = tag.name(), tag.text()
         if name == '@see':
            see_tags.append(string.split(rest,' ',1))
         elif name == '@param':
            param_tags.append(string.split(rest,' ',1))
         elif name == '@return':
            return_tag = rest
         elif name == '@attr':
            attr_tags.append(string.split(rest,' ',1))
         else:
            # unknown tag
            pass
      return "%s%s%s%s%s"%(self.format_inline_see(page, decl, text),
                           self.format_params(param_tags),
                           self.format_attrs(attr_tags),
                           self.format_return(return_tag),
                           self.format_see(page, see_tags, decl))

   def format_inline_see(self, page, decl, text):
      """Formats inline @see tags in the text"""

      #TODO change to link or whatever javadoc uses
      mo = self.re_see.search(text)
      while mo:
         groups, start, end = mo.groups(), mo.start(), mo.end()
         lang = groups[1] or ''
         link = self.find_link(page, groups[2], decl)
         text = text[:start] + link + text[end:]
         end = start + len(link)
         mo = self.re_see.search(text, end)
      return text

   def format_params(self, param_tags):
      """Formats a list of (param, description) tags"""

      if not len(param_tags): return ''
      return div('tag-heading',"Parameters:") + \
             div('tag-section', string.join(
         map(lambda p:"<b>%s</b> - %s"%(p[0],p[1]), param_tags),
         '<br>'))

   def format_attrs(self, attr_tags):
      """Formats a list of (attr, description) tags"""

      if not len(attr_tags): return ''
      table = '<table border=1 class="attr-table">%s</table>'
      row = '<tr><td valign="top" class="attr-table-name">%s</td><td class="attr-table-desc">%s</td></tr>'
      return div('tag-heading',"Attributes:") + \
             table%string.join(map(lambda p,row=row:row%(p[0],p[1]), attr_tags))
   
   def format_return(self, return_tag):
      """Formats a since description string"""

      if not return_tag: return ''
      return div('tag-heading',"Return:")+div('tag-section',return_tag)

   def format_see(self, page, see_tags, decl):
      """Formats a list of (ref,description) tags"""

      if not len(see_tags): return ''
      seestr = div('tag-heading', "See Also:")
      seelist = []
      for see in see_tags:
         ref,desc = see[0], len(see)>1 and see[1] or ''
         link = self.find_link(page, ref, decl)
         seelist.append(link + desc)
      return seestr + div('tag-section', string.join(seelist,'\n<br>\n'))

   def find_link(self, page, ref, decl):
      """Given a "reference" and a declaration, returns a HTML link.
      Various methods are tried to resolve the reference. First the
      parameters are taken off, then we try to split the ref using '.' or
      '::'. The params are added back, and then we try to match this scoped
      name against the current scope. If that fails, then we recursively try
      enclosing scopes.
      """

      # Remove params
      index, label = string.find(ref,'('), ref
      if index >= 0:
         params = ref[index:]
         ref = ref[:index]
      else:
         params = ''
      # Split ref
      ref = string.split(ref, '.')
      if len(ref) == 1:
         ref = string.split(ref[0], '::')
      # Add params back
      ref = ref[:-1] + [ref[-1]+params]
      # Find in all scopes
      scope = list(decl.name())
      while 1:
         entry = self._find_link_at(ref, scope)
         if entry:
            url = rel(page.filename(), entry.link)
            return href(url, label)
         if len(scope) == 0: break
         del scope[-1]
      # Not found
      return label+" "

   def _find_link_at(self, ref, scope):
      # Try scope + ref[0]
      entry = self.processor.toc.lookup(scope+ref[:1])
      if entry:
         # Found.
         if len(ref) > 1:
            # Find sub-refs
            entry = self._find_link_at(ref[1:], scope+ref[:1])
            if entry:
               # Recursive sub-ref was okay!
               return entry 
         else:
            # This was the last scope in ref. Done!
            return entry
      # Try a method name match:
      if len(ref) == 1:
         entry = self._find_method_entry(ref[0], scope)
         if entry: return entry
      # Not found at this scope
      return None

   def _find_method_entry(self, name, scope):
      """Tries to find a TOC entry for a method adjacent to decl. The
      enclosing scope is found using the types dictionary, and the
      realname()'s of all the functions compared to ref."""

      try:
         scope = self.processor.ast.types()[scope]
      except KeyError:
         #print "No parent scope:",decl.name()[:-1]
         return None
      if not scope: return None
      if not isinstance(scope, Type.Declared): return None
      scope = scope.declaration()
      if not isinstance(scope, AST.Scope): return None
      for decl in scope.declarations():
         if isinstance(decl, AST.Function):
            if decl.realname()[-1] == name:
               return self.processor.toc.lookup(decl.name())
      # Failed
      return None

--- NEW FILE: Qtdoc.py ---
# $Id: Qtdoc.py,v 1.1 2003/12/04 21:04:28 stefan Exp $
#
# Copyright (C) 2000 Stephen Davies
# Copyright (C) 2000 Stefan Seefeld
# All rights reserved.
# Licensed to the public under the terms of the GNU LGPL (>= 2),
# see the file COPYING for details.
#

from Javadoc import Javadoc

class Qtdoc(Javadoc):
   """A formatter that uses Qt-style doc tags."""

   _re_see = '@see (([A-Za-z+]+)/)?(([A-Za-z_]+\.?)+)'
   _re_tags = r'((?P<text>.*?)\n)?[ \t]*(?P<tags>\\[a-zA-Z]+[ \t]+.*)'
   _re_seealso = '[ \t]*(,|and|,[ \t]*and)[ \t]*'

   def __init__(self):
      Javadoc.__init__(self)
      self.re_seealso = re.compile(self._re_seealso)

   def parse_text(self, str, decl):

      if str is None: return str
      #str, see = self.extract(self.re_see_line, str)
      see_tags, param_tags, return_tag = [], [], None
      joiner = lambda x,y: len(y) and y[0]=='\\' and x+[y] or x[:-1]+[x[-1]+y]
      str, tags = self.parse_tags(str, joiner)
      # Parse each of the tags
      for line in tags:
         tag, rest = string.split(line,' ',1)
         if tag == '\\sa':
            see_tags.extend(map(lambda x: [x,''], self.re_seealso.split(rest)))
         elif tag == '\\param':
            param_tags.append(string.split(rest,' ',1))
         elif tag == '\\return':
            return_tag = rest
         else:
            # Warning: unknown tag
            pass
      return "%s%s%s%s"%(self.parse_see(str, decl),
                         self.format_params(param_tags),
                         self.format_return(return_tag),
                         self.format_see(see_tags, decl))

   def format_see(self, see_tags, decl):
      """Formats a list of (ref,description) tags"""

      if not len(see_tags): return ''
      seestr = div('tag-see-header', "See Also:")
      seelist = []
      for see in see_tags:
         ref,desc = see[0], len(see)>1 and see[1] or ''
         tag = self.re_seealso.match(ref) and ' %s '%ref or self.find_link(ref, decl)
         seelist.append(span('tag-see', tag+desc))
      return seestr + string.join(seelist,'')

--- NEW FILE: QuoteHTML.py ---
# $Id: QuoteHTML.py,v 1.1 2003/12/04 21:04:28 stefan Exp $
#
# Copyright (C) 2000 Stephen Davies
# Copyright (C) 2000 Stefan Seefeld
# All rights reserved.
# Licensed to the public under the terms of the GNU LGPL (>= 2),
# see the file COPYING for details.
#

from Formatter import Formatter

class QuoteHTML(Formatter):
   """A formatter that quotes HTML characters like angle brackets and
   ampersand. Formats both text and summary."""
   
   def format(self, page, decl, text):
      """Replace angle brackets with HTML codes"""

      text = text.replace('&', '&amp;')
      text = text.replace('<', '&lt;')
      text = text.replace('>', '&gt;')
      return text

   def format_summary(self, page, decl, text):
      """Replace angle brackets with HTML codes"""

      text = text.replace('&', '&amp;')
      text = text.replace('<', '&lt;')
      text = text.replace('>', '&gt;')
      return text

--- NEW FILE: Section.py ---
# $Id: Section.py,v 1.1 2003/12/04 21:04:28 stefan Exp $
#
# Copyright (C) 2000 Stephen Davies
# Copyright (C) 2000 Stefan Seefeld
# All rights reserved.
# Licensed to the public under the terms of the GNU LGPL (>= 2),
# see the file COPYING for details.
#

from Formatter import Formatter
import re

class Section(Formatter):
   """A test formatter"""

   __re_break = '\n[ \t]*\n'

   def __init__(self):

      self.re_break = re.compile(Section.__re_break)

   def format(self, page, decl, text):

      if text is None: return text
      para = '</p>\n<p>'
      mo = self.re_break.search(text)
      while mo:
         start, end = mo.start(), mo.end()
         text = text[:start] + para + text[end:]
         end = start + len(para)
         mo = self.re_break.search(text, end)
      return '<p>%s</p>'%text

--- NEW FILE: __init__.py ---
from Formatter import Formatter
from Javadoc import Javadoc
from Qtdoc import Qtdoc
from QuoteHTML import QuoteHTML
from Section import Section

Index: Formatter.py
===================================================================
RCS file: /cvs/synopsis/Synopsis/Synopsis/Formatters/HTML/Comments/Formatter.py,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -p -d -r1.23 -r1.24
--- Formatter.py	4 Dec 2003 20:01:44 -0000	1.23
+++ Formatter.py	4 Dec 2003 21:04:27 -0000	1.24
@@ -7,63 +7,10 @@
 # see the file COPYING for details.
 #
 
-"""CommentParser, CommentFormatter and derivatives."""
-
 from Synopsis.Processor import Parametrized, Parameter
 from Synopsis import AST, Type, Util
-from Tags import *
-
-import re, string
-
-class CommentFormatter:
-   """A class that takes a Declaration and formats its comments into a string."""
-   def __init__(self, processor):
-      self.__formatters = processor.comment_formatters
-      # Cache the bound methods
-      self.__format_methods = map(lambda f:f.format, self.__formatters)
-      self.__format_summary_methods = map(lambda f:f.format_summary, self.__formatters)
-      # Weed out the unneccessary calls to the empty base methods
-      base = CommentFormatterStrategy.format.im_func
-      self.__format_methods = filter(
-          lambda m, base=base: m.im_func is not base, self.__format_methods)
-      base = CommentFormatterStrategy.format_summary.im_func
-      self.__format_summary_methods = filter(
-          lambda m, base=base: m.im_func is not base, self.__format_summary_methods)
-
-   def format(self, page, decl):
-      """Formats the first comment of the given AST.Declaration.
-      Note that the Linker.Comments.Summarizer CommentProcessor is supposed
-      to have combined all comments first in the Linker stage.
-      @return the formatted text
-      """
-
-      comments = decl.comments()
-      if len(comments) == 0: return ''
-      text = comments[0].text()
-      if not text: return ''
-      # Let each strategy format the text in turn
-      for method in self.__format_methods:
-         text = method(page, decl, text)
-      return text
-
-   def format_summary(self, page, decl):
-      """Formats the summary of the first comment of the given
-      AST.Declaration.
-      Note that the Linker.Comments.Summarizer CommentProcessor is supposed
-      to have combined all comments first in the Linker stage.
-      @return the formatted summary text
-      """
-
-      comments = decl.comments()
-      if len(comments) == 0: return ''
-      text = comments[0].summary()
-      if not text: return ''
-      # Let each strategy format the text in turn
-      for method in self.__format_summary_methods:
-         text = method(page, decl, text)
-      return text
 
-class CommentFormatterStrategy(Parametrized):
+class Formatter(Parametrized):
    """Interface class that takes a comment and formats its summary and/or
    detail strings."""
 
@@ -90,283 +37,3 @@ class CommentFormatterStrategy(Parametri
       """
 
       return text
-
-class QuoteHTML(CommentFormatterStrategy):
-   """A formatter that quotes HTML characters like the angle brackets and the
-   ampersand. Formats both text and summary."""
-   
-   def format(self, page, decl, text):
-      """Replace angle brackets with HTML codes"""
-
-      text = text.replace('&', '&amp;')
-      text = text.replace('<', '&lt;')
-      text = text.replace('>', '&gt;')
-      return text
-
-   def format_summary(self, page, decl, text):
-      """Replace angle brackets with HTML codes"""
-
-      text = text.replace('&', '&amp;')
-      text = text.replace('<', '&lt;')
-      text = text.replace('>', '&gt;')
-      return text
-
-class JavadocFormatter(CommentFormatterStrategy):
-   """A formatter that formats comments similar to Javadoc @tags"""
-
-   # @see IDL/Foo.Bar
-   _re_see = '@see (([A-Za-z+]+)/)?(([A-Za-z_]+\.?)+)'
-   _re_see_line = '^[ \t]*@see[ \t]+(([A-Za-z+]+)/)?(([A-Za-z_]+\.?)+)(\([^)]*\))?([ \t]+(.*))?$'
-   _re_param = '^[ \t]*@param[ \t]+(?P<name>(A-Za-z+]+)([ \t]+(?P<desc>.*))?$'
-
-   def __init__(self):
-      """Create regex objects for regexps"""
-
-      self.re_see = re.compile(self._re_see)
-      self.re_see_line = re.compile(self._re_see_line,re.M)
-
-   def extract(self, regexp, str):
-      """Extracts all matches of the regexp from the text. The MatchObjects
-      are returned in a list"""
-
-      mo = regexp.search(str)
-      ret = []
-      while mo:
-         ret.append(mo)
-         start, end = mo.start(), mo.end()
-         str = str[:start] + str[end:]
-         mo = regexp.search(str, start)
-      return str, ret
-
-   def format(self, page, decl, text):
-      """Format any @tags in the text, and any @tags stored by the JavaTags
-      CommentProcessor in the Linker stage."""
-
-      if text is None: return text
-      see_tags, attr_tags, param_tags, return_tag = [], [], [], None
-      tags = decl.comments()[0].tags()
-      # Parse each of the tags
-      for tag in tags:
-         name, rest = tag.name(), tag.text()
-         if name == '@see':
-            see_tags.append(string.split(rest,' ',1))
-         elif name == '@param':
-            param_tags.append(string.split(rest,' ',1))
-         elif name == '@return':
-            return_tag = rest
-         elif name == '@attr':
-            attr_tags.append(string.split(rest,' ',1))
-         else:
-            # unknown tag
-            pass
-      return "%s%s%s%s%s"%(self.format_inline_see(page, decl, text),
-                           self.format_params(param_tags),
-                           self.format_attrs(attr_tags),
-                           self.format_return(return_tag),
-                           self.format_see(page, see_tags, decl))
-
-   def format_inline_see(self, page, decl, text):
-      """Formats inline @see tags in the text"""
-
-      #TODO change to link or whatever javadoc uses
-      mo = self.re_see.search(text)
-      while mo:
-         groups, start, end = mo.groups(), mo.start(), mo.end()
-         lang = groups[1] or ''
-         link = self.find_link(page, groups[2], decl)
-         text = text[:start] + link + text[end:]
-         end = start + len(link)
-         mo = self.re_see.search(text, end)
-      return text
-
-   def format_params(self, param_tags):
-      """Formats a list of (param, description) tags"""
-
-      if not len(param_tags): return ''
-      return div('tag-heading',"Parameters:") + \
-             div('tag-section', string.join(
-         map(lambda p:"<b>%s</b> - %s"%(p[0],p[1]), param_tags),
-         '<br>'))
-
-   def format_attrs(self, attr_tags):
-      """Formats a list of (attr, description) tags"""
-
-      if not len(attr_tags): return ''
-      table = '<table border=1 class="attr-table">%s</table>'
-      row = '<tr><td valign="top" class="attr-table-name">%s</td><td class="attr-table-desc">%s</td></tr>'
-      return div('tag-heading',"Attributes:") + \
-             table%string.join(map(lambda p,row=row:row%(p[0],p[1]), attr_tags))
-   
-   def format_return(self, return_tag):
-      """Formats a since description string"""
-
-      if not return_tag: return ''
-      return div('tag-heading',"Return:")+div('tag-section',return_tag)
-
-   def format_see(self, page, see_tags, decl):
-      """Formats a list of (ref,description) tags"""
-
-      if not len(see_tags): return ''
-      seestr = div('tag-heading', "See Also:")
-      seelist = []
-      for see in see_tags:
-         ref,desc = see[0], len(see)>1 and see[1] or ''
-         link = self.find_link(page, ref, decl)
-         seelist.append(link + desc)
-      return seestr + div('tag-section', string.join(seelist,'\n<br>\n'))
-
-   def find_link(self, page, ref, decl):
-      """Given a "reference" and a declaration, returns a HTML link.
-      Various methods are tried to resolve the reference. First the
-      parameters are taken off, then we try to split the ref using '.' or
-      '::'. The params are added back, and then we try to match this scoped
-      name against the current scope. If that fails, then we recursively try
-      enclosing scopes.
-      """
-
-      # Remove params
-      index, label = string.find(ref,'('), ref
-      if index >= 0:
-         params = ref[index:]
-         ref = ref[:index]
-      else:
-         params = ''
-      # Split ref
-      ref = string.split(ref, '.')
-      if len(ref) == 1:
-         ref = string.split(ref[0], '::')
-      # Add params back
-      ref = ref[:-1] + [ref[-1]+params]
-      # Find in all scopes
-      scope = list(decl.name())
-      while 1:
-         entry = self._find_link_at(ref, scope)
-         if entry:
-            url = rel(page.filename(), entry.link)
-            return href(url, label)
-         if len(scope) == 0: break
-         del scope[-1]
-      # Not found
-      return label+" "
-
-   def _find_link_at(self, ref, scope):
-      # Try scope + ref[0]
-      entry = self.processor.toc.lookup(scope+ref[:1])
-      if entry:
-         # Found.
-         if len(ref) > 1:
-            # Find sub-refs
-            entry = self._find_link_at(ref[1:], scope+ref[:1])
-            if entry:
-               # Recursive sub-ref was okay!
-               return entry 
-         else:
-            # This was the last scope in ref. Done!
-            return entry
-      # Try a method name match:
-      if len(ref) == 1:
-         entry = self._find_method_entry(ref[0], scope)
-         if entry: return entry
-      # Not found at this scope
-      return None
-
-   def _find_method_entry(self, name, scope):
-      """Tries to find a TOC entry for a method adjacent to decl. The
-      enclosing scope is found using the types dictionary, and the
-      realname()'s of all the functions compared to ref."""
-
-      try:
-         scope = self.processor.ast.types()[scope]
-      except KeyError:
-         #print "No parent scope:",decl.name()[:-1]
-         return None
-      if not scope: return None
-      if not isinstance(scope, Type.Declared): return None
-      scope = scope.declaration()
-      if not isinstance(scope, AST.Scope): return None
-      for decl in scope.declarations():
-         if isinstance(decl, AST.Function):
-            if decl.realname()[-1] == name:
-               return self.processor.toc.lookup(decl.name())
-      # Failed
-      return None
-
-class QtDocFormatter(JavadocFormatter):
-   """A formatter that uses Qt-style doc tags."""
-
-   _re_see = '@see (([A-Za-z+]+)/)?(([A-Za-z_]+\.?)+)'
-   _re_tags = r'((?P<text>.*?)\n)?[ \t]*(?P<tags>\\[a-zA-Z]+[ \t]+.*)'
-   _re_seealso = '[ \t]*(,|and|,[ \t]*and)[ \t]*'
-
-   def __init__(self):
-      JavadocFormatter.__init__(self)
-      self.re_seealso = re.compile(self._re_seealso)
-
-   def parseText(self, str, decl):
-
-      if str is None: return str
-      #str, see = self.extract(self.re_see_line, str)
-      see_tags, param_tags, return_tag = [], [], None
-      joiner = lambda x,y: len(y) and y[0]=='\\' and x+[y] or x[:-1]+[x[-1]+y]
-      str, tags = self.parseTags(str, joiner)
-      # Parse each of the tags
-      for line in tags:
-         tag, rest = string.split(line,' ',1)
-         if tag == '\\sa':
-            see_tags.extend(map(lambda x: [x,''], self.re_seealso.split(rest)))
-         elif tag == '\\param':
-            param_tags.append(string.split(rest,' ',1))
-         elif tag == '\\return':
-            return_tag = rest
-         else:
-            # Warning: unknown tag
-            pass
-      return "%s%s%s%s"%(self.parse_see(str, decl),
-                         self.format_params(param_tags),
-                         self.format_return(return_tag),
-                         self.format_see(see_tags, decl))
-
-   def format_see(self, see_tags, decl):
-      """Formats a list of (ref,description) tags"""
-
-      if not len(see_tags): return ''
-      seestr = div('tag-see-header', "See Also:")
-      seelist = []
-      for see in see_tags:
-         ref,desc = see[0], len(see)>1 and see[1] or ''
-         tag = self.re_seealso.match(ref) and ' %s '%ref or self.find_link(ref, decl)
-         seelist.append(span('tag-see', tag+desc))
-      return seestr + string.join(seelist,'')
-
-class SectionFormatter(CommentFormatterStrategy):
-   """A test formatter"""
-
-   __re_break = '\n[ \t]*\n'
-
-   def __init__(self):
-
-      self.re_break = re.compile(SectionFormatter.__re_break)
-
-   def format(self, page, decl, text):
-      if text is None: return text
-      para = '</p>\n<p>'
-      mo = self.re_break.search(text)
-      while mo:
-         start, end = mo.start(), mo.end()
-         text = text[:start] + para + text[end:]
-         end = start + len(para)
-         mo = self.re_break.search(text, end)
-      return '<p>%s</p>'%text
-
-commentFormatters = {
-    'none' : CommentFormatterStrategy,
-    'ssd' : CommentFormatterStrategy,
-    'java' : CommentFormatterStrategy,
-    'quotehtml' : QuoteHTML,
-    'summary' : CommentFormatterStrategy,
-    'javadoc' : JavadocFormatter,
-    'qtdoc' : QtDocFormatter,
-    'section' : SectionFormatter,
-}
-
-





More information about the Synopsis-changes mailing list