Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Formatter/ASCII.py
    1| # $Id: ASCII.py,v 1.32 2003/01/27 06:53:36 chalky Exp $
    2| #
    3| # This file is a part of Synopsis.
    4| # Copyright (C) 2000, 2001 Stefan Seefeld
    5| # Copyright (C) 2000, 2001 Stephen Davies
    6| #
    7| # Synopsis is free software; you can redistribute it and/or modify it
    8| # under the terms of the GNU General Public License as published by
    9| # the Free Software Foundation; either version 2 of the License, or
   10| # (at your option) any later version.
   11| #
   12| # This program is distributed in the hope that it will be useful,
   13| # but WITHOUT ANY WARRANTY; without even the implied warranty of
   14| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15| # General Public License for more details.
   16| #
   17| # You should have received a copy of the GNU General Public License
   18| # along with this program; if not, write to the Free Software
   19| # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   20| # 02111-1307, USA.
   21| #
   22| # $Log: ASCII.py,v $
   23| # Revision 1.32  2003/01/27 06:53:36  chalky
   24| # Added macro support for C++.
   25| #
   26| # Revision 1.31  2002/10/27 12:06:11  chalky
   27| # Fix funcptr parameters
   28| #
   29| # Revision 1.30  2002/10/26 04:15:53  chalky
   30| # Fix typo in method name
   31| #
   32| # Revision 1.29  2002/10/20 15:38:07  chalky
   33| # Much improved template support, including Function Templates.
   34| #
   35| # Revision 1.28  2001/08/02 03:25:09  chalky
   36| # Reworked handling of enumerators for use in synopsis-qt GUI
   37| #
   38| # Revision 1.27  2001/07/28 02:41:34  chalky
   39| # Minor sanity fix
   40| #
   41| # Revision 1.26  2001/07/19 04:00:17  chalky
   42| # New .syn file format. Added -b, -c flags
   43| #
   44| # Revision 1.25  2001/05/25 13:45:49  stefan
   45| # fix problem with getopt error reporting
   46| #
   47| # Revision 1.24  2001/02/13 06:55:23  chalky
   48| # Made synopsis -l work again
   49| #
   50| # Revision 1.23  2001/02/13 06:35:20  chalky
   51| # Added config_obj to format() args to prevent exception.
   52| #
   53| # Revision 1.22  2001/02/06 16:02:23  chalky
   54| # Fixes
   55| #
   56| # Revision 1.21  2001/01/31 06:51:24  stefan
   57| # add support for '-v' to all modules; modified toc lookup to use additional url as prefix
   58| #
   59| # Revision 1.20  2001/01/24 01:38:36  chalky
   60| # Added docstrings to all modules
   61| #
   62| # Revision 1.19  2001/01/22 19:54:41  stefan
   63| # better support for help message
   64| #
   65| # Revision 1.18  2001/01/22 17:06:15  stefan
   66| # added copyright notice, and switched on logging
   67| #
   68| """
   69| Outputs the AST in plain ascii format similar to input.
   70| """
   71| 
   72| # THIS-IS-A-FORMATTER
   73| import sys, getopt, os, os.path, string
   74| from Synopsis.Core import Type, AST, Util
   75| 
   76| verbose = 0
   77| comment_str = "// %s\n"
   78| 
   79| class ASCIIFormatter(AST.Visitor, Type.Visitor):
   80|     """
   81|     outputs as ascii. This is to test for features
   82|     still missing. The output should be compatible
   83|     with the input...
   84|     """
   85|     def __init__(self, os):
   86|         self.__indent = 0
   87|         self.__istring = "  "
   88|         self.__os = os
   89|         self.__scope = []
   90|         self.__axs = AST.DEFAULT
   91|         self.__axs_stack = []
   92|         self.__axs_string = ('default:\n','public:\n','protected:\n','private:\n')
   93|         self.__enumers = []
   94|         self.__id_holder = None
   95|     def indent(self):
   96|         self.__os.write(self.__istring * self.__indent)
   97|     def incr(self): self.__indent = self.__indent + 1
   98|     def decr(self): self.__indent = self.__indent - 1
   99|     def scope(self): return self.__scope
  100|     def set_scope(self, name): self.__scope = list(name)
  101|     def enterScope(self, name): self.__scope.append(name),self.incr()
  102|     def leaveScope(self): self.__scope.pop(),self.decr()
  103|     def write(self, text): self.__os.write(text)
  104| 
  105|     def formatType(self, type, id_holder = None):
  106|         if type is None: return '(unknown)'
  107|         if id_holder: self.__id_holder = id_holder
  108|         type.accept(self)
  109|         if id_holder: self.__id_holder = None
  110|         return self.__type
  111|     
  112|     #################### Type Visitor ###########################################
  113| 
  114|     def visitBaseType(self, type):
  115|         self.__type = Util.ccolonName(type.name())
  116|         
  117|     def visitDependent(self, type):
  118|         self.__type = type.name()[-1]
  119|         
  120|     def visitUnknown(self, type):
  121|         self.__type = Util.ccolonName(type.name(), self.scope())
  122|         
  123|     def visitDeclared(self, type):
  124|         self.__type = Util.ccolonName(type.name(), self.scope())
  125|         
  126|     def visitModifier(self, type):
  127|         aliasStr = self.formatType(type.alias())
  128|         premod = map(lambda x:x+" ", type.premod())
  129|         self.__type = "%s%s%s"%(string.join(premod,''), aliasStr, string.join(type.postmod(),''))
  130|             
  131|     def visitParametrized(self, type):
  132|         temp = self.formatType(type.template())
  133|         params = map(self.formatType, type.parameters())
  134|         self.__type = "%s<%s>"%(temp,string.join(params, ", "))
  135| 
  136|     def visitFunctionType(self, type):
  137|         ret = self.formatType(type.returnType())
  138|         params = map(self.formatType, type.parameters())
  139|         premod = string.join(type.premod(),'')
  140|         if self.__id_holder:
  141|             ident = self.__id_holder[0]
  142|             del self.__id_holder[0]
  143|         else:
  144|             ident = ''
  145|         self.__type = "%s(%s%s)(%s)"%(ret,premod,ident,string.join(params,", "))
  146| 
  147|     def visitTemplate(self, type):
  148|         self.visitDeclared(type)
  149|         #self.__type = "template<"+string.join(map(self.formatType, type.parameters()),",")+">"+self.__type
  150|         
  151|     ### AST visitor
  152| 
  153|     def visitDeclaration(self, decl):
  154|         axs = decl.accessibility()
  155|         if axs != self.__axs:
  156|             self.decr(); self.indent(); self.incr()
  157|             self.write(self.__axs_string[axs])
  158|             self.__axs = axs
  159|         self.writeComments(decl.comments())
  160| 
  161|     def visitMacro(self, macro):
  162|         self.visitDeclaration(macro)
  163|         self.indent()
  164|         params = ''
  165|         if macro.parameters() is not None:
  166|             params = '(' + string.join(macro.parameters(), ', ') + ')'
  167|         self.write("#define %s%s %s\n"%(macro.name()[-1], params, macro.text()))
  168|     
  169|     def writeComments(self, comments):
  170|         for comment in comments:
  171|             text = comment.text()
  172|             if not text: continue
  173|             lines = string.split(text, "\n")
  174|             for line in lines:
  175|                self.indent()
  176|                self.write(comment_str%line)
  177| 
  178|     def visitTypedef(self, typedef):
  179|         self.visitDeclaration(typedef)
  180|         self.indent()
  181|         dstr = ""
  182|         # Figure out the type:
  183|         alias = self.formatType(typedef.alias())
  184|         # Figure out the declarators:
  185|         # for declarator in typedef.declarators():
  186|         #     dstr = dstr + declarator.name()[-1]
  187|         #     if declarator.sizes() is None: continue
  188|         #     for size in declarator.sizes():
  189|         #      dstr = dstr + "[%d]"
  190|         self.write("typedef %s %s;\n"%(
  191|             alias, typedef.name()[-1]
  192|         ))
  193| 
  194|     def visitModule(self, module):
  195|         self.visitDeclaration(module)
  196|         self.indent()
  197|         self.write("%s %s {\n"%(module.type(),module.name()[-1]))
  198|         self.enterScope(module.name()[-1])
  199|         #for type in module.types(): type.output(self)
  200|         for declaration in module.declarations():
  201|             declaration.accept(self)
  202|         self.leaveScope()
  203|         self.indent()
  204|         self.write("}\n")
  205| 
  206|     def visitMetaModule(self, module):
  207|         self.visitDeclaration(module)
  208|         for decl in module.module_declarations():
  209|             self.visitDeclaration(decl)
  210|         # since no comments:
  211|         self.visitModule(module)
  212| 
  213|     def visitClass(self, clas):
  214|         self.visitDeclaration(clas)
  215|         self.indent()
  216|         self.write("%s %s"%(clas.type(),clas.name()[-1]))
  217|         if len(clas.parents()):
  218|             self.write(": ")
  219|           p = []
  220|             for parent in clas.parents():
  221|                p.append(self.formatType(parent.parent()))
  222|                 #p.append("%s"%(Util.ccolonName(parent.parent().name(),clas.name()),))
  223|             self.write(string.join(p, ", "))
  224|         self.write(" {\n")
  225|         self.enterScope(clas.name()[-1])
  226|         self.__axs_stack.append(self.__axs)
  227|         if clas.type() == 'struct': self.__axs = AST.PUBLIC
  228|         elif clas.type() == 'class': self.__axs = AST.PRIVATE
  229|         else: self.__axs = AST.DEFAULT
  230|         #for type in clas.types(): type.output(self)
  231|         #for operation in clas.operations(): operation.output(self)
  232|         for declaration in clas.declarations():
  233|             declaration.accept(self)
  234|         self.__axs = self.__axs_stack.pop()
  235|         self.leaveScope()
  236|         self.indent()
  237|         self.write("};\n")
  238| 
  239|     def visitInheritance(self, inheritance):
  240|         for attribute in inheritance.attributes(): self.write(attribute + " ")
  241|         self.write(inheritance.parent().identifier())
  242| 
  243|     def visitParameter(self, parameter):
  244|         spacer = lambda x: str(x)+" "
  245|         premod = string.join(map(spacer,parameter.premodifier()),'')
  246|         id_holder = [parameter.identifier()]
  247|         type = self.formatType(parameter.type(), id_holder)
  248|         postmod = string.join(map(spacer,parameter.postmodifier()),'')
  249|         name = ""
  250|         value = ""
  251|         if id_holder and len(parameter.identifier()) != 0:
  252|             name = " " + parameter.identifier()
  253|         if len(parameter.value()) != 0:
  254|             value = " = %s"%parameter.value()
  255|         self.__params.append(premod + type + postmod + name + value)
  256| 
  257|     def visitFunction(self, function):
  258|         self.visitOperation(function)
  259| 
  260|     def visitOperation(self, operation):
  261|         self.visitDeclaration(operation)
  262|         self.indent()
  263|         for modifier in operation.premodifier(): self.write(modifier + " ")
  264|         retStr = self.formatType(operation.returnType())
  265|         name = operation.realname()
  266|         if operation.language() == "IDL" and operation.type() == "attribute":
  267|             self.write("attribute %s %s"%(retStr,name[-1]))
  268|         else:
  269|             if operation.language() == "C++" and len(name)>1 and name[-1] in [name[-2],"~"+name[-2]]:
  270|                self.write("%s("%name[-1])
  271|          else:
  272|                if retStr: self.write(retStr+" ")
  273|                self.write("%s("%name[-1])
  274|             self.__params = []
  275|             for parameter in operation.parameters(): parameter.accept(self)
  276|             params = string.join(self.__params, ", ")
  277|             self.write(params + ")")
  278|         for modifier in operation.postmodifier(): self.write(modifier + " ")
  279|         self.write(";\n")
  280| 
  281|     def visitVariable(self, var):
  282|         self.visitDeclaration(var)
  283|         name = var.name
  284|         self.indent()
  285|         self.write("%s %s;\n"%(self.formatType(var.vtype()),var.name()[-1]))
  286| 
  287|     def visitEnum(self, enum):
  288|         self.visitDeclaration(enum)
  289|         self.indent()
  290|         istr = self.__istring * (self.__indent+1)
  291|         self.write("enum %s {"%enum.name()[-1])
  292|         self.__enumers = []
  293|         comma = ''
  294|         for enumer in enum.enumerators():
  295|             self.write(comma+'\n'+istr)
  296|             enumer.accept(self)
  297|             comma = ','
  298|         self.write("\n")
  299|         self.indent()
  300|         self.write("}\n")
  301| 
  302|     def visitEnumerator(self, enumer):
  303|         self.writeComments(enumer.comments())
  304|         if enumer.value() == "":
  305|             self.write("%s"%enumer.name()[-1])
  306|         else:
  307|             self.write("%s = %s"%(enumer.name()[-1], enumer.value()))
  308|     
  309|     def visitConst(self, const):
  310|         self.visitDeclaration(const)
  311|         ctype = self.formatType(const.ctype())
  312|         self.indent()
  313|         self.__os.write("%s %s = %s;\n"%(ctype,const.name()[-1],const.value()))
  314| 
  315| 
  316| def usage():
  317|     """Print usage to stdout"""
  318|     print \
  319| """
  320|   -o <file>                            Output file
  321|   -b                                   Bold comments
  322|   -c <colour>                          Coloured comments, colour = 0 to 15 
  323| """
  324| 
  325| def __parseArgs(args):
  326|     global output, verbose, show_bold, show_colour, comment_str
  327|     output = sys.stdout
  328|     show_bold = 0
  329|     show_colour = None
  330|     try:
  331|         opts,remainder = getopt.getopt(args, "o:vbc:")
  332|     except getopt.error, e:
  333|         sys.stderr.write("Error in arguments: " + str(e) + "\n")
  334|         sys.exit(1)
  335| 
  336|     for opt in opts:
  337|         o,a = opt
  338| 
  339|         if o == "-o": output = open(a, "w")
  340|         elif o == "-v": verbose = 1
  341|         elif o == "-b": show_bold = 1
  342|         elif o == "-c": show_colour = int(a)
  343| 
  344|     if show_colour is not None: 
  345|         comment_str = "\033[3%d%sm// %%s\033[m\n"%(
  346|             show_colour % 8, 
  347|             (show_colour >= 8) and ";1" or "")
  348|     elif show_bold:
  349|         comment_str = "\033[1m// %s\033[m\n"
  350| 
  351| def print_types(types):
  352|     keys = types.keys()
  353|     keys.sort()
  354|     for name in keys:
  355|         type = types[name]
  356|         clas = type.__class__
  357|         if isinstance(type, Type.Declared):
  358|             clas = type.declaration().__class__
  359|         try:
  360|             print "%s\t%s"%(string.split(clas.__name__,'.')[-1], Util.ccolonName(name))
  361|         except:
  362|             print "name ==",name
  363|          raise
  364| 
  365| def format(args, ast, config_obj):
  366|     __parseArgs(args)
  367|     formatter = ASCIIFormatter(output)
  368|     #for type in types:
  369|     #    type.output(formatter)
  370|     for declaration in ast.declarations():
  371|         declaration.accept(formatter)
  372| 
  373|     # print_types(types)