[Top][All Lists]
[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
- [certi-cvs] certi/scripts GenMsgBase.py CERTI_Message.msg G...,
certi-cvs <=