certi-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[certi-cvs] certi/scripts GenMsgBase.py CERTI_Message.msg G...


From: certi-cvs
Subject: [certi-cvs] certi/scripts GenMsgBase.py CERTI_Message.msg G...
Date: Fri, 05 Mar 2010 13:57:08 +0000

CVSROOT:        /sources/certi
Module name:    certi
Changes by:     Eric NOULARD <erk>      10/03/05 13:57:08

Modified files:
        scripts        : GenMsgBase.py CERTI_Message.msg GenMsgCXX.py 
                         GenerateMessages.py 
Added files:
        scripts        : GenMsgAST.py 

Log message:
        Update Message Generator in order to handle
        native "combined" types.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/certi/scripts/GenMsgBase.py?cvsroot=certi&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/certi/scripts/CERTI_Message.msg?cvsroot=certi&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/certi/scripts/GenMsgCXX.py?cvsroot=certi&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/certi/scripts/GenerateMessages.py?cvsroot=certi&r1=1.31&r2=1.32
http://cvs.savannah.gnu.org/viewcvs/certi/scripts/GenMsgAST.py?cvsroot=certi&rev=1.1

Patches:
Index: GenMsgBase.py
===================================================================
RCS file: /sources/certi/certi/scripts/GenMsgBase.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- GenMsgBase.py       4 Mar 2010 09:28:30 -0000       1.1
+++ GenMsgBase.py       5 Mar 2010 13:57:08 -0000       1.2
@@ -19,7 +19,7 @@
 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 ## USA
 ##
-## $Id: GenMsgBase.py,v 1.1 2010/03/04 09:28:30 erk Exp $
+## $Id: GenMsgBase.py,v 1.2 2010/03/05 13:57:08 erk Exp $
 ## ----------------------------------------------------------------------------
 
 """
@@ -32,6 +32,7 @@
 import logging
 import sys 
 import datetime
+import GenMsgAST
     
 class CodeGenerator(object):
     """
@@ -177,7 +178,14 @@
             # Generate native type
             for native in self.AST.natives:            
                 self.writeComment(stream, native)
-                stream.write("native %s\n\n" % native.name)          
+                stream.write("native %s {\n" % native.name)
+                self.indent()
+                if (native.hasRepresentation()):
+                    stream.write(self.getIndent()+ "representation " + 
native.getRepresentation()+"\n")
+                for l in native.languages.values():
+                    stream.write(self.getIndent()+"language " +  l.name + "    
 ["+l.statement+"]\n")
+                self.unIndent()
+                stream.write("}\n")
                 
             # Generate enum
             for enum in self.AST.enums:
@@ -205,6 +213,16 @@
                     stream.write(" {\n")
                 
                 for field in msg.fields:
+                    if (isinstance(field, 
GenMsgAST.MessageType.CombinedField)):
+                        stream.write("        combined %s {" % (field.typeid))
+                        self.writeComment(stream, field)
+                        for cfield in field.fields:
+                            stream.write("            %s %s %s " % 
(cfield.qualifier,cfield.typeid.name,cfield.name))
+                            if cfield.hasDefaultValue():
+                                stream.write("[default=%s] " % 
cfield.defaultValue)                                    
+                            self.writeComment(stream, cfield)
+                        stream.write("        }\n")    
+                    else:
                     stream.write("        %s %s %s " % 
(field.qualifier,field.typeid.name,field.name))
                     if field.hasDefaultValue():
                         stream.write("[default=%s] " % field.defaultValue)     
                               

Index: CERTI_Message.msg
===================================================================
RCS file: /sources/certi/certi/scripts/CERTI_Message.msg,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- CERTI_Message.msg   27 Feb 2010 16:45:19 -0000      1.10
+++ CERTI_Message.msg   5 Mar 2010 13:57:08 -0000       1.11
@@ -136,6 +136,12 @@
     language CXX [#include "certi.hh"]
 }
 
+native AttributeHandleValuePairSet {
+    representation combine
+    language CXX   [#include "RTItypes.hh"]
+    language Java  [import hla.rti.SuppliedAttributes] 
+}
+
 native AttributeValue_t {
        representation string
        language CXX [#include "certi.hh"]
@@ -268,8 +274,10 @@
 message M_Update_Attribute_Values : merge Message {
         required ObjectClassHandle  objectClass
            required ObjectHandle       object
+           combine AttributeHandleValuePairSet {
         repeated AttributeHandle    attributes
-        repeated AttributeValue_t   values // FIXME check this one
+           repeated AttributeValue_t      values
+        }
         optional EventRetractionHandle eventRetraction
 }
 
@@ -283,8 +291,10 @@
 message M_Reflect_Attribute_Values : merge Message {
            required ObjectClassHandle  objectClass
            required ObjectHandle       object
+           combine AttributeHandleValuePairSet {
         repeated AttributeHandle    attributes
-        repeated AttributeValue_t   values // FIXME check this one
+           repeated AttributeValue_t   values
+        }
         optional EventRetractionHandle eventRetraction
 }
 

Index: GenMsgCXX.py
===================================================================
RCS file: /sources/certi/certi/scripts/GenMsgCXX.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- GenMsgCXX.py        4 Mar 2010 09:28:30 -0000       1.1
+++ GenMsgCXX.py        5 Mar 2010 13:57:08 -0000       1.2
@@ -19,7 +19,7 @@
 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 ## USA
 ##
-## $Id: GenMsgCXX.py,v 1.1 2010/03/04 09:28:30 erk Exp $
+## $Id: GenMsgCXX.py,v 1.2 2010/03/05 13:57:08 erk Exp $
 ## ----------------------------------------------------------------------------
 
 """
@@ -27,6 +27,7 @@
 C++ Backend Generator
 """
 import logging
+import GenMsgAST
 import GenMsgBase    
 import sys
 import os   
@@ -38,7 +39,7 @@
     """
     
     def generatorName(cls):
-        return "C++"
+        return "CXX"
     generatorName = classmethod(generatorName)
     
     
@@ -246,6 +247,7 @@
        else:
            (headerProtectMacroName,ext) = os.path.splitext(self.AST.name)
         headerProtectMacroName = "%s_HH" % headerProtectMacroName.upper()
+            
         stream.write("#ifndef %s\n"%headerProtectMacroName)
         stream.write("#define %s\n"%headerProtectMacroName)        
         # add necessary standard and global includes
@@ -257,7 +259,7 @@
         # add include coming from native type specification 
         stream.write(self.commentLineBeginWith+" ****-**** Includes coming 
from native types ****-****\n")
         for native in self.AST.natives:
-            line = native.getLanguage("CXX").statement
+            line = native.getLanguage(self.generatorName()).statement
             # we are only interested in native "include" statement
             if line.find("#include")>=0 and (not line in self.included.keys()):
                 self.writeComment(stream, native)
@@ -285,6 +287,7 @@
                     self.typedefed[line]=1                                    
             
             # Generate enum
+            lastname = ""
             for enum in self.AST.enums:            
                 self.writeComment(stream, enum)
                 stream.write(self.getIndent())
@@ -297,6 +300,7 @@
                         stream.write(self.getIndent())
                         stream.write("%s = %d, " % 
(enumval.name,enumval.value))                
                         first=False
+                        self.writeComment(stream, enumval)
                     else:
                         stream.write(self.getIndent())
                        if (enumval.name==lastname):
@@ -322,7 +326,6 @@
                     virtual = ""
                 
                 self.indent()
-                
                 # begin public
                 stream.write(self.getIndent()+"public:\n") 
                 self.indent()
@@ -341,6 +344,10 @@
                     # specific getter/setter
                     stream.write(self.getIndent()+self.commentLineBeginWith+" 
specific Getter(s)/Setter(s)\n")
                     for field in msg.fields:
+                        if 
(isinstance(field,GenMsgAST.MessageType.CombinedField)):
+                            for cfield in field.fields:
+                                self.writeOneGetterSetter(stream,cfield)
+                        else:
                         self.writeOneGetterSetter(stream,field)
                     # the show method
                     stream.write(self.getIndent()+self.commentLineBeginWith+" 
the show method\n")
@@ -353,6 +360,10 @@
                 stream.write(self.getIndent()+"protected:\n")
                 self.indent()
                 for field in msg.fields:
+                    if (isinstance(field,GenMsgAST.MessageType.CombinedField)):
+                        for cfield in field.fields:
+                            self.writeDeclarationFieldStatement(stream,cfield)
+                    else:
                     self.writeDeclarationFieldStatement(stream,field)          
          
                 self.unIndent()
                 # end protected  
@@ -517,7 +528,7 @@
                 
stream.write("msgBuffer."+methodName+"("+field.name+indexField+");\n")
             else:
                 # We may have to vast in order to enforce conversion
-                if isinstance(field.typeid,NativeType):
+                if isinstance(field.typeid,GenMsgAST.NativeType):
                    stream.write(field.name+indexField+" = 
static_cast<"+field.typeid.name+">(msgBuffer."+methodName+"());\n")
                 else:
                    stream.write(field.name+indexField+" = 
msgBuffer."+methodName+"();\n")
@@ -573,6 +584,13 @@
         self.unIndent()
         stream.write(self.getIndent()+("} /* end of %s::%s */ \n\n" % 
(receiver[1],receiver[2])))
     
+    def applyToFields(self,stream,fields,applyObject):
+        for field in fields:
+            if (isinstance(field, GenMsgAST.MessageType.CombinedField)):
+                for cfield in field.fields:
+                    applyObject(stream,cfield)
+            else:
+                applyObject(stream,field)                        
         
     def generateBody(self,stream,factoryOnly=False):
         """
@@ -603,8 +621,7 @@
                 stream.write(self.getIndent()+"this->type = 
"+msg.name.upper().replace("M_","Message::",1)+";\n")
                 # Write init value if any was provided
                 if len(msg.fields)>0:
-                    for field in msg.fields:
-                        self.writeInitFieldStatement(stream,field)             
           
+                    self.applyToFields(stream, msg.fields, 
self.writeInitFieldStatement)                                         
                 self.unIndent()
                 stream.write(self.getIndent()+"}\n\n")
                 # Generate Destructor                
@@ -625,8 +642,7 @@
                         
stream.write(self.getIndent()+"Super::serialize(msgBuffer);\n")
                     stream.write(self.getIndent()+self.commentLineBeginWith)
                     stream.write("Specific serialization code\n")
-                    for field in msg.fields:
-                        self.writeSerializeFieldStatement(stream,field)
+                    self.applyToFields(stream, msg.fields, 
self.writeSerializeFieldStatement)                    
                     self.unIndent()
                     stream.write(self.getIndent()+"}\n\n")
                     # end serialize method
@@ -640,8 +656,7 @@
                         
stream.write(self.getIndent()+"Super::deserialize(msgBuffer);\n")
                     stream.write(self.getIndent()+self.commentLineBeginWith)
                     stream.write("Specific deserialization code\n")
-                    for field in msg.fields:
-                        self.writeDeSerializeFieldStatement(stream,field)
+                    self.applyToFields(stream, msg.fields, 
self.writeDeSerializeFieldStatement)                    
                     self.unIndent()
                     stream.write(self.getIndent()+"}\n\n")
                     # end deserialize method
@@ -655,8 +670,7 @@
                         stream.write(self.getIndent()+"Super::show(out);\n")
                     stream.write(self.getIndent()+self.commentLineBeginWith)
                     stream.write("Specific show code\n")
-                    for field in msg.fields:
-                        self.writeShowFieldStatement(stream,field)
+                    self.applyToFields(stream, msg.fields, 
self.writeShowFieldStatement)                  
                     stream.write(self.getIndent()+"out << \"[%s -End]\" << 
std::endl;" % msg.name)
                     self.unIndent()
                     stream.write(self.getIndent()+"}\n\n")
@@ -671,3 +685,5 @@
             self.writeFactoryReceiver(stream)                                  
                          
                         
         self.closeNamespaces(stream)                        
+        
+               

Index: GenerateMessages.py
===================================================================
RCS file: /sources/certi/certi/scripts/GenerateMessages.py,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -b -r1.31 -r1.32
--- GenerateMessages.py 4 Mar 2010 09:28:30 -0000       1.31
+++ GenerateMessages.py 5 Mar 2010 13:57:08 -0000       1.32
@@ -19,7 +19,7 @@
 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 ## USA
 ##
-## $Id: GenerateMessages.py,v 1.31 2010/03/04 09:28:30 erk Exp $
+## $Id: GenerateMessages.py,v 1.32 2010/03/05 13:57:08 erk Exp $
 ## ----------------------------------------------------------------------------
 
 """
@@ -69,12 +69,15 @@
 mainlogger.setLevel(logging.ERROR)
 mainlogger.addHandler(stdoutHandler)
 
-# FIXME TODO: implement automatic loading of additionnal 
-# languages
+# Load AST related classes
+import GenMsgAST
+# Load backend specific language generator
+# FIXME TODO: implement automatic loading of additionnal languages
 import GenMsgBase
 import GenMsgCXX
 import GenMsgPython
 import GenMsgJava
+import GenMsgAST
 
 generatorBackends = dict()
 generatorBackends[GenMsgBase.MsgSpecGenerator.generatorName().lower()] = 
GenMsgBase.MsgSpecGenerator
@@ -103,7 +106,7 @@
 verbose=False
 factoryOnly=False
 gentype="header"
-language="MsgSpec"
+language=GenMsgBase.MsgSpecGenerator.generatorName()
 output=sys.stdout
 
 # Parse command line options
@@ -146,6 +149,7 @@
    'required' : 'REQUIRED',
    'optional' : 'OPTIONAL',
    'repeated' : 'REPEATED',
+   'combine'  : 'COMBINE',
    'onoff'    : 'ONOFF_T',
    'bool'     : 'BOOL_T',
    'string'   : 'STRING_T',
@@ -252,7 +256,7 @@
 
 # Error handling rule
 def t_error(t):
-    print "Illegal character '%s'" % t.value[0]
+    t.lexer.logger.error("Illegal character '%s'" % t.value[0])
     t.lexer.skip(1)
 
 # Build the PLY lexer
@@ -262,401 +266,6 @@
 lexer = ply.lex.lex(debug=False)
 lexer.logger = lexerlogger
 
-class ASTElement(object):
-    """
-    The base class for all Abstract Syntax Tree element.
-
-    @param name: the name of the element
-    @type name: C{string}
-    @param comment: the comment attached to this element.
-                    may be C{None}
-    @type comment: C{CommentBlock}   
-    """
-    def __init__(self,name):        
-        self.__name     = name
-        self.__comment  = None
-        self.__linespan = None
-        self.logger = logging.Logger("ASTElement")
-        self.logger.setLevel(logging.ERROR)
-        self.logger.addHandler(stdoutHandler)
-    
-    def __getName(self):
-        return self.__name    
-    def __setName(self,name):        
-        self.__name = name
-    # pythonic getter/setter using properties    
-    name = property(fget=__getName,fset=__setName,fdel=None, doc="The name of 
the C{ASTElement}")    
-    
-    def hasComment(self):
-        return self.__comment!=None
-    
-    def __getComment(self):
-        return self.__comment    
-    def __setComment(self,comment):
-        if isinstance(comment,type("")):
-            pass
-        else:
-            self.logger.info("Adding comment %s to element %s" % 
(comment.lines,self.name))
-            self.__comment = comment
-    # pythonic getter/setter using properties    
-    comment = property(fget=__getComment,fset=__setComment,fdel=None, doc="The 
comment block attached to the C{ASTElement}")
-    
-    def __getLinespan(self):
-        return self.__linespan    
-    def __setLinespan(self,linespan):        
-        self.__linespan = linespan
-    # pythonic getter/setter using properties    
-    linespan = property(fget=__getLinespan,fset=__setLinespan,fdel=None, 
doc="The line span of this C{ASTElement} in the original file")    
-    
-
-class MessageAST(ASTElement):
-    """
-    Message Abstract Syntax Tree root class.
-    
-    This class represents the abstraction of the message description
-    language including all the features represented by corresponding
-    class field. Object instance of C{MessageAST} may be used by a 
-    language generator in order to generate code for the target language.
-    
-    @param package: the package which the generated message will belong
-                    this will be used by the specific AST generator
-    @type package:  C{Package}                     
-    @param natives: the set of native types described in this
-                          C{MessageAST}
-    @type natives: C{set} of C{NativeType}
-    @param messages: the set of messages described in this C{MessageAST}
-    @type messages: C{set} of C{MessageType}          
-    
-    """
-    def __init__(self,name):
-        super(MessageAST,self).__init__(name=name)
-        self.__package            = None
-        self.__factory            = None
-        self.__nativeTypes        = []
-        self.__messageTypes       = []
-        self.__enumTypes          = []
-        # The types dictionary is initialized with builtin types
-        self.__types                = {'onoff' : ASTElement("onoff"),
-                                       'bool' : ASTElement("bool"),
-                                       'string' : ASTElement("string"),
-                                       'byte' : ASTElement("byte"),
-                                       'int8' : ASTElement("int8"),
-                                       'uint8' : ASTElement("uint8"),
-                                       'int16' : ASTElement("int16"),
-                                       'uint16' : ASTElement("uint16"),
-                                       'int32' : ASTElement("int32"),
-                                       'uint32' : ASTElement("uint32"),   
-                                       'int64' : ASTElement("int64"),
-                                       'uint64' : ASTElement("uint64"),
-                                       'float' : ASTElement("float"),
-                                       'double' : ASTElement("double")}
-        self.__ultimateElement      = None                
-        self.logger = logging.Logger("MessageAST")
-        self.logger.setLevel(logging.ERROR)
-        self.logger.addHandler(stdoutHandler)
-        
-    def hasPackage(self):
-        return self.__package != None
-    def __getPackage(self):
-        return self.__package
-    def __setPackage(self,package):
-        self.__package = package
-    # pythonic getter/setter using properties   
-    package = property(fget=__getPackage,fset=__setPackage,fdel=None,doc=None)
-
-    def hasFactory(self):
-        return self.__factory != None
-    def __getFactory(self):
-        return self.__factory
-    def __setFactory(self,factory):
-        self.__factory = factory
-    # pythonic getter/setter using properties   
-    factory = property(fget=__getFactory,fset=__setFactory,fdel=None,doc=None)
-        
-    def __getNativeTypes(self):
-        return self.__nativeTypes  
-    # pythonic getter/setter using properties   
-    natives = property(fget=__getNativeTypes,fset=None,fdel=None,doc=None)
-    
-    def __getMessageTypes(self):
-        return self.__messageTypes  
-    # pythonic getter/setter using properties      
-    messages = property(fget=__getMessageTypes,fset=None,fdel=None,doc=None)
-    
-    def __getEnumTypes(self):
-        return self.__enumTypes
-    # pythonic getter/setter using properties   
-    enums = property(fget=__getEnumTypes,fset=None,fdel=None,doc=None)         
-        
-        
-    def add(self,any):
-        """ 
-        Add an ASTElement to the AST.
-        
-        The parser will call this method as soons as it has
-        built the appropriate ASTElement sub-class.
-        
-        @param any: the object to be added to the tree
-        @type any: some sub-class of C{ASTElement}, see: G{ASTElement}
-          
-        """
-        if any == None:
-            self.logger.error("<None> given to AST some rule aren't finished") 
   
-        else:                     
-            self.logger.debug("Add %s %s" % (type(any).__name__,any.name))
-            # Typename must be unique
-            if self.isDefined(any.name):                
-                self.logger.error("%s already defined in the AST" % any.name)
-                self.logger.error(" --> Check lines (%d,%d) " % any.linespan + 
"and (%d,%d)" % self.getType(any.name).linespan+ " of <%s>" % self.name)        
                  
-            elif isinstance(any,EnumType):            
-                self.addEnumType(any)                            
-            elif isinstance(any,NativeType):
-                self.addNativeType(any)
-            elif isinstance(any,MessageType):
-                self.addMessageType(any)
-            elif isinstance(any,Package):
-                self.package = any
-            elif isinstance(any,Factory):
-                self.factory = any
-            # Handle comment block preceding other AST element
-            elif isinstance(any,CommentBlock):                
-                if self.__ultimateElement != None:
-                    # attach the comment block to the preceding
-                    # AST element (recursion is backtracking)
-                    # The list of comment line should be reversed
-                    any.lines.reverse()
-                    self.__ultimateElement.comment = any
-                else:
-                    pass               
-            else:            
-                self.logger.error("<%s> not handle [yet]" % any)               
    
-            self.__ultimateElement    = any            
-            
-    def addMessageType(self,message): 
-        """
-        Add a message type to the AST.
-        
-        @param message: The message type to be added
-        @type message: C{MessageType}  
-        """       
-        self.__messageTypes.append(message)
-        self.__types[message.name] = message
-        
-    def addEnumType(self,enumType):
-        """
-        Add an enum type to the AST.
-        
-        @param enumType: The enum type to be added
-        @type enumType: C{EnumType}  
-        """        
-        self.__enumTypes.append(enumType)
-        self.__types[enumType.name] = enumType               
-    
-    def addNativeType(self,native):
-        """
-        Add a native type to the AST.
-        
-        @param native: The message type to be added
-        @type native: C{NativeType}  
-        """
-        self.__nativeTypes.append(native)
-        self.__types[native.name] = native
-        
-    def isDefined(self,typename):
-        """
-        Return true if the typename is know in this AST.
-        
-        @param typename: the name of the type
-        @type typename: C{string}  
-        """
-        return self.getType(typename)!=None        
-    
-    def getType(self,typename):
-        if isinstance(typename,type("")):
-            if typename in self.__types.keys():
-                return self.__types[typename]
-            else:
-                return None
-        else:
-            return typename        
-    
-    def __repr__(self):
-        res = "AST with <%d> native type(s), <%d> enum, <%d> message type(s)" 
% (len(self.natives),len(self.enums),len(self.messages))
-        if (self.hasFactory()):
-            res = res + " and factory <%s> "% self.factory.name
-        if (self.hasPackage()):
-            res = res + " in package <%s>" % self.package
-        return res    
-    
-class CommentBlock(ASTElement):
-    """
-    Represents a block of comment
-    
-    A C{CommentBlock} has lines which is a list of C{string}.
-    @param lines: the comments lines
-    @type lines: C{list} of C{string}  
-    """
-    def __init__(self,content,isAtEOL):
-        """
-        C{CommentBlock} constructor
-        """
-        super(CommentBlock,self).__init__(name="ANY Comment Block")
-        self.lines=[content]
-        self.__isAtEOL=isAtEOL
-        
-    def __getisAtEOL(self):
-        return self.__isAtEOL
-    # pythonic getter/setter using properties   
-    isAtEOL = property(fget=__getisAtEOL,fset=None,fdel=None,doc="True if the 
comment is optional")   
-    
-class Package(ASTElement):
-    """
-    Represents a package.
-    
-    A C{Package} is a simple C{ASTElement} whose
-    name is a C{string} containing a
-    dot-separated IDs like: "fr.onera.certi"
-    """
-    def __init__(self,name):        
-        super(Package,self).__init__(name)                        
-          
-    def __repr__(self):
-        return "package %s" % self.name
-
-class Factory(ASTElement):
-    """
-    Represents a factory.
-    
-    A C{Factory} is anC{ASTElement} whose
-    name is a C{string}.
-    """
-    def __init__(self,name,creator,receiver):        
-        super(Factory,self).__init__(name)
-        self.creator  = creator
-        self.receiver = receiver
-          
-    def __repr__(self):
-        res="factory %s" % self.name
-        res=res+ ", creator = %s %s(%s)" % creator
-        res=res+ ", receiver = %s %s(%s)" % receiver
-        return res    
-     
-class NativeType(ASTElement):
-    """ 
-    Represents a native message type.
-    
-    A C{NaptiveType} is a simple C{ASTElement} whose
-    name is the name the native type.
-    """
-    def __init__(self,name,lines):
-        super(NativeType,self).__init__(name=name)
-        # store language line list in a dictionnary
-        # in order to ease retrieval
-        self.languages = dict()
-        self.representation = None
-        for l in lines:
-            if isinstance(l,NativeType.LanguageLine):
-                self.languages[l.name] = l
-            else:
-                self.representation = l.representation
-        
-    def __repr__(self):
-        return "native %s" % self.name
-    
-    def getLanguage(self,language):
-        if language in self.languages.keys():
-            return self.languages[language]
-
-    def getRepresentation(self):
-        return self.representation
-     
-    class LanguageLine(ASTElement):
-        """ Represents a Language Line Value
-        """
-        def __init__(self,name,value):
-            super(NativeType.LanguageLine,self).__init__(name=name)    
-            self.statement = value.strip("[]")                
-
-    class RepresentationLine(ASTElement):
-        """ Represents a Representation Line Value
-        """
-        def __init__(self,value):
-            
super(NativeType.RepresentationLine,self).__init__(name='representation')
-            self.representation = value
-                    
-class MessageType(ASTElement):
-    """ 
-    Represents a message type.
-    
-    @param fields: the fields of this C{MessageType}
-    @type fields: C{list} of C{MessageType.MessageField}
-    @param merge: the merger of this C{MessageType}
-    @type merge: a C{MessageType}  
-    """
-    def __init__(self,name,fields,merge):
-        super(MessageType,self).__init__(name=name)
-        self.fields = fields
-        self.merge  = merge                    
-    
-    def __repr__(self):
-        res = "message %s " % self.name
-        return res
-        
-    def hasMerge(self):
-        return self.merge != None
-    
-    class MessageField(ASTElement):
-        """ Represents a message field            
-        """
-        def __init__(self,qualifier,typeid,name,defaultValue=None):
-            super(MessageType.MessageField,self).__init__(name=name)
-            self.qualifier    = qualifier
-            """ The field qualifier, which may be
-                 - repeated
-                 - optional
-                 - required 
-            """
-            self.typeid       = typeid
-            """ The type of the field
-            """
-            self.defaultValue = defaultValue
-            """ The default value for this field
-            """
-            
-        def hasDefaultValue(self):
-            return self.defaultValue != None
-                
-class EnumType(ASTElement):
-    """ Represents an enum type 
-    """
-    def __init__(self,name,values):
-        super(EnumType,self).__init__(name=name)
-        # rebuild dictionary with value from the list                     
-        self.values = []
-        lastval     = -1        
-        for val in values:                                    
-            if (val.value==None):
-                val.value = lastval+1
-                self.values.append(val)
-                lastval += 1
-            else:
-                self.values.append(val)                           
-                lastval = val.value
-        
-    def __repr__(self):
-        res = "Enum %s {\n" % self.name
-        for val in self.values:            
-            res = res + "  " + str(val[0]) + " = " + str(val[1]) + ", \n"
-        res = res + "}"
-        return res                 
-               
-    class EnumValue(ASTElement):
-        """ Represents an Enum Value
-        """
-        def __init__(self,name,value):
-            super(EnumType.EnumValue,self).__init__(name=name)    
-            self.value = value
-            
 def p_statement_list(p):
     '''statement_list : statement 
                       | statement statement_list'''
@@ -675,14 +284,14 @@
     '''comment_block : COMMENT
                      | COMMENT comment_block'''
     if len(p)==2:                 
-        p[0]=CommentBlock(p[1].strip('/'),isAtEOL=False)
+        p[0]=GenMsgAST.CommentBlock(p[1].strip('/'),isAtEOL=False)
     else:
         p[0]=p[2]
         p[0].lines.append(p[1].strip('/'))        
     
 def p_package(p):
     '''package : PACKAGE package_id'''    
-    p[0]=Package(p[2])
+    p[0]=GenMsgAST.Package(p[2])
     p[0].linespan = (p.linespan(1)[0],p.linespan(2)[1])
     
 def p_package_id(p):
@@ -695,7 +304,7 @@
 
 def p_factory(p):
     '''factory : FACTORY ID LBRACE factory_creator factory_receiver RBRACE'''
-    p[0] = Factory(p[2],p[4],p[5])
+    p[0] = GenMsgAST.Factory(p[2],p[4],p[5])
     p[0].linespan = (p.linespan(1)[0],p.linespan(6)[1])
 
 def p_factory_creator(p):
@@ -712,15 +321,15 @@
                | MESSAGE ID COLON MERGE ID LBRACE RBRACE 
                | MESSAGE ID COLON MERGE ID LBRACE field_list RBRACE'''
     if len(p)==5:        
-        p[0] = MessageType(p[2],[],None)        
+        p[0] = GenMsgAST.MessageType(p[2],[],None)        
     elif len(p)==6:
         p[4].reverse()
-        p[0] = MessageType(p[2],p[4],None)
+        p[0] = GenMsgAST.MessageType(p[2],p[4],None)
     elif len(p)==8:
-        p[0] = MessageType(p[2],[],p[5])
+        p[0] = GenMsgAST.MessageType(p[2],[],p[5])
     elif len(p)==9:
         p[7].reverse()
-        p[0] = MessageType(p[2],p[7],p[5])                                    
+        p[0] = GenMsgAST.MessageType(p[2],p[7],p[5])                           
         
     p[0].linespan = (p.linespan(1)[0],p.linespan(len(p)-1)[1]) 
     
 def p_native(p): 
@@ -728,7 +337,7 @@
     # we should reverse the language list
     # because the parse build it the other way around (recursive way)
     p[4].reverse()
-    p[0]=NativeType(p[2],p[4])    
+    p[0]=GenMsgAST.NativeType(p[2],p[4])    
     p[0].linespan = (p.linespan(1)[0],p.linespan(5)[1])
     
 def p_native_line_list(p):
@@ -750,18 +359,19 @@
 
 def p_language_line(p):
     '''language_line : LANGUAGE ID LANGLINE'''
-    p[0]=NativeType.LanguageLine(p[2],p[3])
+    p[0]=GenMsgAST.NativeType.LanguageLine(p[2],p[3])
     
 def p_representation_line(p):
-    '''representation_line : REPRESENTATION typeid'''
-    p[0]=NativeType.RepresentationLine(p[2])
+    '''representation_line : REPRESENTATION typeid
+                        | REPRESENTATION COMBINE'''
+    p[0]=GenMsgAST.NativeType.RepresentationLine(p[2])
         
 def p_enum(p):
     'enum : ENUM ID LBRACE enum_value_list RBRACE'
     # we should reverse the enum value list
     # because the parse build it the other way around (recursive way)
     p[4].reverse()
-    p[0] = EnumType(p[2],p[4])
+    p[0] = GenMsgAST.EnumType(p[2],p[4])
     p[0].linespan = (p.linespan(1)[0],p.linespan(5)[1])
     
 def p_empty(p):
@@ -773,7 +383,7 @@
                         | empty'''
     # we may store the comment text for future use
     if len(p) > 1 and isinstance(p[1],type("")) :
-        p[0] = CommentBlock(p[1].strip('/'),isAtEOL=True)
+        p[0] = GenMsgAST.CommentBlock(p[1].strip('/'),isAtEOL=True)
         p[0].linespan = p.linespan(1)        
     else:
         p[0] = ""         
@@ -800,10 +410,10 @@
     # Build a pair (ID,value)
     # value may be None    
     if len(p)>3:
-        p[0] = EnumType.EnumValue(p[1],p[3])
+        p[0] = GenMsgAST.EnumType.EnumValue(p[1],p[3])
         p[0].linespan = (p.linespan(1)[0],p.linespan(3)[1])
     else:
-        p[0] = EnumType.EnumValue(p[1],None)
+        p[0] = GenMsgAST.EnumType.EnumValue(p[1],None)
         p[0].linespan = p.linespan(1)     
 
 def p_field_list(p):
@@ -817,14 +427,20 @@
 
 def p_field_spec(p):
     '''field_spec : qualifier typeid ID eol_comment
-                  | qualifier typeid ID LBRACE DEFAULT EQUAL value RBRACE 
eol_comment'''
+                  | qualifier typeid ID LBRACE DEFAULT EQUAL value RBRACE 
eol_comment
+                  | COMBINE typeid LBRACE field_list RBRACE eol_comment'''
     
     if len(p)==5:
-        p[0] = MessageType.MessageField(p[1],p[2],p[3],None)
+        p[0] = GenMsgAST.MessageType.MessageField(p[1],p[2],p[3],None)
         p[0].comment = p[4]
         p[0].linespan = (p.linespan(1)[0],p.linespan(4)[1])
+    elif len(p)==7:
+        p[4].reverse()
+        p[0] = GenMsgAST.MessageType.CombinedField(p[2],p[4])
+        p[0].comment = p[5]
+        p[0].linespan = (p.linespan(1)[0],p.linespan(4)[1])
     else:                
-        p[0] = MessageType.MessageField(p[1],p[2],p[3],p[7])
+        p[0] = GenMsgAST.MessageType.MessageField(p[1],p[2],p[3],p[7])
         p[0].comment = p[9]   
         p[0].linespan = (p.linespan(1)[0],p.linespan(8)[1])
 
@@ -867,10 +483,9 @@
              | STRING_VALUE'''    
     p[0]=p[1]
     
-# Compute column. 
-#     input is the input text string
-#     token is a token instance
 def find_column(input,token):
+    '''input is the input text string
+    token is a token instance'''
     last_cr = input.rfind('\n',0,token.lexpos)
     if last_cr < 0:
         last_cr = 0
@@ -882,103 +497,7 @@
         msg = "Syntax error at '%s' on line %d column %d (token type is '%s')" 
% (p.value,p.lineno,find_column(p.lexer.lexdata, p),p.type)
     else:
         msg = "Syntax error at '%s' on line %d (token type is '%s')" % 
(p.value,p.lineno,p.type)
-    print msg
-    
-
-class ASTChecker(object):
-    """
-    The Purpose of this class is to check AST properties. 
-        
-    """
-    def __init__(self):
-        self.logger = logging.Logger("ASTChecker")
-        self.logger.setLevel(logging.ERROR)
-        self.logger.addHandler(stdoutHandler)        
-    
-    def check(self,AST):
-        """
-        Check the AST.
-        
-        @param AST: the AST to be checked
-        @type AST: C{MessageAST}  
-        """
-        
-        # check if the supplied object has appropriate super type
-        # @todo: note that we may just require to have the appropriate
-        #        fields and not being sub-class of MesssageAST.
-        #        this could be done with introspection.
-        #        see: http://docs.python.org/library/inspect.html
-        if not isinstance(AST, MessageAST):
-           self.logger.error("The supplied object is not an instance of 
MessageAST: <%s>" % type(AST))
-           AST.checked = False 
-           return
-       
-        # check if all field used in message have known types
-        # At the same time build the enum values for MessageTypes
-        enumval = EnumType.EnumValue("NOT_USED",None)
-        enumval.type = None
-        msgTypeEnumVals = [enumval]
-        for msg in AST.messages:
-            enumval      = EnumType.EnumValue(msg.name.upper(),None)
-            enumval.type = msg.name
-            msgTypeEnumVals.append(enumval)
-            for f in msg.fields:
-                if not AST.isDefined(f.typeid):
-                    self.logger.fatal("The type <%s> used for field <%s.%s> is 
unknown (not a builtin, nor native, nor message)" % (f.typeid,msg.name,f.name))
-                    self.logger.fatal(" --> Check lines (%d,%d)" % 
(f.linespan) + " of <%s>" % AST.name)
-                    AST.checked = False
-                    return
-                else:                   
-                   f.typeid = AST.getType(f.typeid)
-        enumval      = EnumType.EnumValue("LAST",None)
-        enumval.type = None                                    
-        msgTypeEnumVals.append(enumval)
-        AST.eMessageType = 
EnumType(AST.name.split(".")[0]+"_MessageType",msgTypeEnumVals) 
-        AST.add(AST.eMessageType)
-         
-
-        # @todo
-        # Should check if the default value of a field
-        # has the appropriate type (builtin types)
-        # and that field with defined type have NO
-        # default value
-                                
-        # check if merger are either native or message
-        # @todo should check that merger is not an enum
-        for msg in AST.messages:
-            if msg.hasMerge():
-                if not AST.isDefined(msg.merge):
-                    self.logger.fatal("The merge target <%s> of message <%s> 
is unknown (not a builtin, nor native, nor message)" % (msg.merge,msg.name))
-                    self.logger.fatal(" --> Check lines (%d,%d)" % 
(msg.linespan) + " of <%s>" % AST.name )                    
-                    AST.checked = False
-                    return
-                else:
-                    msg.merge = AST.getType(msg.merge)
-                    
-        # check the factory methods
-        if AST.hasFactory():                        
-            if not AST.isDefined(AST.factory.creator[0]):
-                self.logger.fatal("The return type <%s> of the creator factory 
method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.creator[0])
-                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
-                AST.checked = False
-                return
-            if not AST.isDefined(AST.factory.creator[2]):
-                self.logger.fatal("The parameter type <%s> of the creator 
factory method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.creator[2])
-                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
-                AST.checked = False
-                return
-            if not AST.isDefined(AST.factory.receiver[0]):
-                self.logger.fatal("The return type <%s> of the receiver 
factory method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.receiver[0])
-                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
-                AST.checked = False
-                return
-            if not AST.isDefined(AST.factory.receiver[2]):
-                self.logger.fatal("The parameter type <%s> of the receiver 
factory method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.receiver[2])
-                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
-                AST.checked = False
-                return
-                
-        AST.checked = True                  
+    parserlogger.fatal(msg)
                                                                                
  
 # Build the PLY parser
 parserlogger = logging.Logger("MessageParser")
@@ -996,7 +515,7 @@
     sys.exit()
     
 lexer.lineno = 1
-parser.AST = MessageAST(inputFile)
+parser.AST = GenMsgAST.MessageAST(inputFile)
 parser.parse(msgFile.read(),lexer=lexer)
 parser.AST.messages.reverse()
 parser.AST.enums.reverse()
@@ -1005,7 +524,7 @@
 mainlogger.info("Parse succeeded %s" % (parser.AST))
 
 mainlogger.info("Checking AST properties....")
-checker = ASTChecker()
+checker = GenMsgAST.ASTChecker()
 checker.check(parser.AST)
 if parser.AST.checked:    
     mainlogger.info("AST properties checked Ok.")

Index: GenMsgAST.py
===================================================================
RCS file: GenMsgAST.py
diff -N GenMsgAST.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ GenMsgAST.py        5 Mar 2010 13:57:08 -0000       1.1
@@ -0,0 +1,546 @@
+#!/usr/bin/env python
+
+## ----------------------------------------------------------------------------
+## CERTI - HLA RunTime Infrastructure
+## Copyright (C) 2002-2005  ONERA
+##
+## This program is free software ; you can redistribute it and/or
+## modify it under the terms of the GNU Lesser 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
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this program ; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+## USA
+##
+## $Id: GenMsgAST.py,v 1.1 2010/03/05 13:57:08 erk Exp $
+## ----------------------------------------------------------------------------
+
+"""
+The CERTI Message Generator.
+Generator AST classes.
+"""
+
+import os
+import getopt, sys
+import datetime
+import logging
+# Build some logger related objects
+stdoutHandler = logging.StreamHandler(sys.stdout)
+                                      
+class ASTElement(object):
+    """
+    The base class for all Abstract Syntax Tree element.
+
+    @param name: the name of the element
+    @type name: C{string}
+    @param comment: the comment attached to this element.
+                    may be C{None}
+    @type comment: C{CommentBlock}   
+    """
+    
+    def __init__(self,name):        
+        self.__name     = name
+        self.__comment  = None
+        self.__linespan = None
+        self.logger = logging.Logger("ASTElement")
+        self.logger.setLevel(logging.ERROR)
+        self.logger.addHandler(stdoutHandler)
+    
+    def __getName(self):
+        return self.__name    
+    def __setName(self,name):        
+        self.__name = name
+    # pythonic getter/setter using properties    
+    name = property(fget=__getName,fset=__setName,fdel=None, doc="The name of 
the C{ASTElement}")    
+    
+    def hasComment(self):
+        return self.__comment!=None
+    
+    def __getComment(self):
+        return self.__comment    
+    def __setComment(self,comment):
+        if isinstance(comment,type("")):
+            pass
+        else:
+            self.logger.info("Adding comment %s to element %s" % 
(comment.lines,self.name))
+            self.__comment = comment
+    # pythonic getter/setter using properties    
+    comment = property(fget=__getComment,fset=__setComment,fdel=None, doc="The 
comment block attached to the C{ASTElement}")
+    
+    def __getLinespan(self):
+        return self.__linespan    
+    def __setLinespan(self,linespan):        
+        self.__linespan = linespan
+    # pythonic getter/setter using properties    
+    linespan = property(fget=__getLinespan,fset=__setLinespan,fdel=None, 
doc="The line span of this C{ASTElement} in the original file")    
+    
+class MessageAST(ASTElement):
+    """
+    Message Abstract Syntax Tree root class.
+    
+    This class represents the abstraction of the message description
+    language including all the features represented by corresponding
+    class field. Object instance of C{MessageAST} may be used by a 
+    language generator in order to generate code for the target language.
+    
+    @param package: the package which the generated message will belong
+                    this will be used by the specific AST generator
+    @type package:  C{Package}                     
+    @param natives: the set of native types described in this
+                          C{MessageAST}
+    @type natives: C{set} of C{NativeType}
+    @param messages: the set of messages described in this C{MessageAST}
+    @type messages: C{set} of C{MessageType}          
+    
+    """
+    def __init__(self,name):
+        super(MessageAST,self).__init__(name=name)
+        self.__package            = None
+        self.__factory            = None
+        self.__nativeTypes        = []
+        self.__messageTypes       = []
+        self.__enumTypes          = []
+        # The types dictionary is initialized with builtin types
+        self.__types                = {'onoff' : ASTElement("onoff"),
+                                       'bool' : ASTElement("bool"),
+                                       'string' : ASTElement("string"),
+                                       'byte' : ASTElement("byte"),
+                                       'int8' : ASTElement("int8"),
+                                       'uint8' : ASTElement("uint8"),
+                                       'int16' : ASTElement("int16"),
+                                       'uint16' : ASTElement("uint16"),
+                                       'int32' : ASTElement("int32"),
+                                       'uint32' : ASTElement("uint32"),   
+                                       'int64' : ASTElement("int64"),
+                                       'uint64' : ASTElement("uint64"),
+                                       'float' : ASTElement("float"),
+                                       'double' : ASTElement("double")}
+        self.__ultimateElement      = None                
+        self.logger = logging.Logger("MessageAST")
+        self.logger.setLevel(logging.ERROR)
+        self.logger.addHandler(stdoutHandler)
+        
+    def hasPackage(self):
+        return self.__package != None
+    def __getPackage(self):
+        return self.__package
+    def __setPackage(self,package):
+        self.__package = package
+    # pythonic getter/setter using properties   
+    package = property(fget=__getPackage,fset=__setPackage,fdel=None,doc=None)
+
+    def hasFactory(self):
+        return self.__factory != None
+    def __getFactory(self):
+        return self.__factory
+    def __setFactory(self,factory):
+        self.__factory = factory
+    # pythonic getter/setter using properties   
+    factory = property(fget=__getFactory,fset=__setFactory,fdel=None,doc=None)
+        
+    def __getNativeTypes(self):
+        return self.__nativeTypes  
+    # pythonic getter/setter using properties   
+    natives = property(fget=__getNativeTypes,fset=None,fdel=None,doc=None)
+    
+    def __getMessageTypes(self):
+        return self.__messageTypes  
+    # pythonic getter/setter using properties      
+    messages = property(fget=__getMessageTypes,fset=None,fdel=None,doc=None)
+    
+    def __getEnumTypes(self):
+        return self.__enumTypes
+    # pythonic getter/setter using properties   
+    enums = property(fget=__getEnumTypes,fset=None,fdel=None,doc=None)         
+        
+        
+    def add(self,any):
+        """ 
+        Add an ASTElement to the AST.
+        
+        The parser will call this method as soons as it has
+        built the appropriate ASTElement sub-class.
+        
+        @param any: the object to be added to the tree
+        @type any: some sub-class of C{ASTElement}, see: G{ASTElement}
+          
+        """
+        if any == None:
+            self.logger.error("<None> given to AST some rule aren't finished") 
   
+        else:                     
+            self.logger.debug("Add %s %s" % (type(any).__name__,any.name))
+            # Typename must be unique
+            if self.isDefined(any.name):                
+                self.logger.error("%s already defined in the AST" % any.name)
+                self.logger.error(" --> Check lines (%d,%d) " % any.linespan + 
"and (%d,%d)" % self.getType(any.name).linespan+ " of <%s>" % self.name)        
                  
+            elif isinstance(any,EnumType):            
+                self.addEnumType(any)                            
+            elif isinstance(any,NativeType):
+                self.addNativeType(any)
+            elif isinstance(any,MessageType):
+                self.addMessageType(any)
+            elif isinstance(any,Package):
+                self.package = any
+            elif isinstance(any,Factory):
+                self.factory = any
+            # Handle comment block preceding other AST element
+            elif isinstance(any,CommentBlock):                
+                if self.__ultimateElement != None:
+                    # attach the comment block to the preceding
+                    # AST element (recursion is backtracking)
+                    # The list of comment line should be reversed
+                    any.lines.reverse()
+                    self.__ultimateElement.comment = any
+                else:
+                    pass               
+            else:            
+                self.logger.error("<%s> not handle [yet]" % any)               
    
+            self.__ultimateElement    = any            
+            
+    def addMessageType(self,message): 
+        """
+        Add a message type to the AST.
+        
+        @param message: The message type to be added
+        @type message: C{MessageType}  
+        """       
+        self.__messageTypes.append(message)
+        self.__types[message.name] = message
+        
+    def addEnumType(self,enumType):
+        """
+        Add an enum type to the AST.
+        
+        @param enumType: The enum type to be added
+        @type enumType: C{EnumType}  
+        """        
+        self.__enumTypes.append(enumType)
+        self.__types[enumType.name] = enumType               
+    
+    def addNativeType(self,native):
+        """
+        Add a native type to the AST.
+        
+        @param native: The message type to be added
+        @type native: C{NativeType}  
+        """
+        self.__nativeTypes.append(native)
+        self.__types[native.name] = native
+        
+    def isDefined(self,typename):
+        """
+        Return true if the typename is know in this AST.
+        
+        @param typename: the name of the type
+        @type typename: C{string}  
+        """
+        return self.getType(typename)!=None        
+    
+    def getType(self,typename):
+        if isinstance(typename,type("")):
+            if typename in self.__types.keys():
+                return self.__types[typename]
+            else:
+                return None
+        else:
+            return typename        
+    
+    def __repr__(self):
+        res = "AST with <%d> native type(s), <%d> enum, <%d> message type(s)" 
% (len(self.natives),len(self.enums),len(self.messages))
+        if (self.hasFactory()):
+            res = res + " and factory <%s> "% self.factory.name
+        if (self.hasPackage()):
+            res = res + " in package <%s>" % self.package
+        return res    
+    
+class CommentBlock(ASTElement):
+    """
+    Represents a block of comment
+    
+    A C{CommentBlock} has lines which is a list of C{string}.
+    @param lines: the comments lines
+    @type lines: C{list} of C{string}  
+    """
+    
+    def __init__(self,content,isAtEOL):
+        """
+        C{CommentBlock} constructor
+        """
+        super(CommentBlock,self).__init__(name="ANY Comment Block")
+        self.lines=[content]
+        self.__isAtEOL=isAtEOL
+        
+    def __getisAtEOL(self):
+        return self.__isAtEOL
+    # pythonic getter/setter using properties   
+    isAtEOL = property(fget=__getisAtEOL,fset=None,fdel=None,doc="True if the 
comment is optional")   
+    
+class Package(ASTElement):
+    """
+    Represents a package.
+    
+    A C{Package} is a simple C{ASTElement} whose
+    name is a C{string} containing a
+    dot-separated IDs like: "fr.onera.certi"
+    """
+    def __init__(self,name):        
+        super(Package,self).__init__(name)                        
+          
+    def __repr__(self):
+        return "package %s" % self.name
+
+class Factory(ASTElement):
+    """
+    Represents a factory.
+    
+    A C{Factory} is anC{ASTElement} whose
+    name is a C{string}.
+    """
+    def __init__(self,name,creator,receiver):        
+        super(Factory,self).__init__(name)
+        self.creator  = creator
+        self.receiver = receiver
+          
+    def __repr__(self):
+        res="factory %s" % self.name
+        res=res+ ", creator = %s %s(%s)" % creator
+        res=res+ ", receiver = %s %s(%s)" % receiver
+        return res    
+     
+class NativeType(ASTElement):
+    """ 
+    Represents a native message type.
+    
+    A C{NaptiveType} is a simple C{ASTElement} whose
+    name is the name the native type.
+    """
+    def __init__(self,name,lines):
+        super(NativeType,self).__init__(name=name)
+        # store language line list in a dictionnary
+        # in order to ease retrieval
+        self.languages = dict()
+        self.representation = None
+        for l in lines:
+            if isinstance(l,NativeType.LanguageLine):
+                self.languages[l.name] = l
+            else:
+                self.representation = l.representation
+        
+    def __repr__(self):
+        return "native %s" % self.name
+    
+    def getLanguage(self,language):
+        if language in self.languages.keys():
+            return self.languages[language]
+        
+    def hasRepresentation(self):
+        return self.representation != None
+
+    def getRepresentation(self):
+        return self.representation
+     
+    class LanguageLine(ASTElement):
+        """ Represents a Language Line Value
+        """
+        def __init__(self,name,value):
+            super(NativeType.LanguageLine,self).__init__(name=name)    
+            self.statement = value.strip("[]")                
+
+    class RepresentationLine(ASTElement):
+        """ Represents a Representation Line Value
+        """
+        def __init__(self,value):
+            
super(NativeType.RepresentationLine,self).__init__(name='representation')
+            self.representation = value
+                    
+class MessageType(ASTElement):
+    """ 
+    Represents a message type.
+    
+    @param fields: the fields of this C{MessageType}
+    @type fields: C{list} of C{MessageType.MessageField}
+    @param merge: the merger of this C{MessageType}
+    @type merge: a C{MessageType}  
+    @param combine: a combined set of fields
+    """
+    def __init__(self,name,fields,merge):
+        super(MessageType,self).__init__(name=name)
+        self.fields        = fields
+        self.merge         = merge                 
+    
+    def __repr__(self):
+        res = "message %s " % self.name
+        return res
+        
+    def hasMerge(self):
+        return self.merge != None
+    
+    class CombinedField(ASTElement):
+        def __init__(self,typeid,fields):
+            super(MessageType.CombinedField,self).__init__(name="Combined")
+            self.typeid = typeid
+            self.fields = fields            
+    
+    class MessageField(ASTElement):
+        """ Represents a message field            
+        """
+        def __init__(self,qualifier,typeid,name,defaultValue=None):
+            super(MessageType.MessageField,self).__init__(name=name)
+            self.qualifier    = qualifier
+            """ The field qualifier, which may be
+                 - repeated
+                 - optional
+                 - required 
+            """
+            self.typeid       = typeid
+            """ The type of the field
+            """
+            self.defaultValue = defaultValue
+            """ The default value for this field
+            """
+            
+        def hasDefaultValue(self):
+            return self.defaultValue != None
+                
+class EnumType(ASTElement):
+    """ Represents an enum type 
+    """
+    def __init__(self,name,values):
+        super(EnumType,self).__init__(name=name)
+        # rebuild dictionary with value from the list                     
+        self.values = []
+        lastval     = -1        
+        for val in values:                                    
+            if (val.value==None):
+                val.value = lastval+1
+                self.values.append(val)
+                lastval += 1
+            else:
+                self.values.append(val)                           
+                lastval = val.value
+        
+    def __repr__(self):
+        res = "Enum %s {\n" % self.name
+        for val in self.values:            
+            res = res + "  " + str(val[0]) + " = " + str(val[1]) + ", \n"
+        res = res + "}"
+        return res                 
+               
+    class EnumValue(ASTElement):
+        """ Represents an Enum Value
+        """
+        def __init__(self,name,value):
+            super(EnumType.EnumValue,self).__init__(name=name)    
+            self.value = value
+                
+class ASTChecker(object):
+    """
+    The Purpose of this class is to check AST properties. 
+        
+    """
+    def __init__(self):
+        self.logger = logging.Logger("ASTChecker")
+        self.logger.setLevel(logging.ERROR)
+        self.logger.addHandler(stdoutHandler)      
+    
+    def checkMessageFields(self,msg,AST):  
+        for f in msg.fields:
+            if not AST.isDefined(f.typeid):
+                self.logger.fatal("The type <%s> used for field <%s.%s> is 
unknown (not a builtin, nor native, nor message)" % (f.typeid,msg.name,f.name))
+                self.logger.fatal(" --> Check lines (%d,%d)" % (f.linespan) + 
" of <%s>" % AST.name)
+                AST.checked = False
+                return
+            else:
+                if (isinstance(f,MessageType.MessageField)):                   
+                    f.typeid = AST.getType(f.typeid)
+                elif (isinstance(f,MessageType.CombinedField)):
+                    self.checkMessageFields(f,AST)
+                else:
+                    self.logger.fatal("Unknown MessageField type %s" % f.str())
+                    
+                
+    def check(self,AST):
+        """
+        Check the AST.
+        
+        @param AST: the AST to be checked
+        @type AST: C{MessageAST}  
+        """
+        
+        # check if the supplied object has appropriate super type
+        # @todo: note that we may just require to have the appropriate
+        #        fields and not being sub-class of MesssageAST.
+        #        this could be done with introspection.
+        #        see: http://docs.python.org/library/inspect.html
+        if not isinstance(AST, MessageAST):
+           self.logger.error("The supplied object is not an instance of 
MessageAST: <%s>" % type(AST))
+           AST.checked = False 
+           return
+       
+        # check if all field used in message have known types
+        # At the same time build the enum values for MessageTypes
+        enumval = EnumType.EnumValue("NOT_USED",None)
+        enumval.type = None
+        msgTypeEnumVals = [enumval]
+        for msg in AST.messages:
+            enumval      = EnumType.EnumValue(msg.name.upper(),None)
+            enumval.type = msg.name
+            msgTypeEnumVals.append(enumval)
+            self.checkMessageFields(msg,AST)            
+        enumval      = EnumType.EnumValue("LAST",None)
+        enumval.type = None                                    
+        msgTypeEnumVals.append(enumval)
+        AST.eMessageType = 
EnumType(AST.name.split(".")[0]+"_MessageType",msgTypeEnumVals) 
+        AST.add(AST.eMessageType)
+         
+
+        # @todo
+        # Should check if the default value of a field
+        # has the appropriate type (builtin types)
+        # and that field with defined type have NO
+        # default value
+                                
+        # check if merger are either native or message
+        # @todo should check that merger is not an enum
+        for msg in AST.messages:
+            if msg.hasMerge():
+                if not AST.isDefined(msg.merge):
+                    self.logger.fatal("The merge target <%s> of message <%s> 
is unknown (not a builtin, nor native, nor message)" % (msg.merge,msg.name))
+                    self.logger.fatal(" --> Check lines (%d,%d)" % 
(msg.linespan) + " of <%s>" % AST.name )                    
+                    AST.checked = False
+                    return
+                else:
+                    msg.merge = AST.getType(msg.merge)
+                    
+        # check the factory methods
+        if AST.hasFactory():                        
+            if not AST.isDefined(AST.factory.creator[0]):
+                self.logger.fatal("The return type <%s> of the creator factory 
method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.creator[0])
+                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
+                AST.checked = False
+                return
+            if not AST.isDefined(AST.factory.creator[2]):
+                self.logger.fatal("The parameter type <%s> of the creator 
factory method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.creator[2])
+                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
+                AST.checked = False
+                return
+            if not AST.isDefined(AST.factory.receiver[0]):
+                self.logger.fatal("The return type <%s> of the receiver 
factory method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.receiver[0])
+                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
+                AST.checked = False
+                return
+            if not AST.isDefined(AST.factory.receiver[2]):
+                self.logger.fatal("The parameter type <%s> of the receiver 
factory method is unknown (not a builtin, nor native, nor message)" % 
AST.factory.receiver[2])
+                self.logger.fatal(" --> Check lines (%d,%d)" % 
(AST.factory.linespan) + " of <%s>" % AST.name )
+                AST.checked = False
+                return
+                
+        AST.checked = True                  
+                                                                               
  
\ No newline at end of file




reply via email to

[Prev in Thread] Current Thread [Next in Thread]