llmessage.py
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:12k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. """
  2. @file llmessage.py
  3. @brief Message template parsing and compatiblity
  4. $LicenseInfo:firstyear=2007&license=mit$
  5. Copyright (c) 2007-2010, Linden Research, Inc.
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. $/LicenseInfo$
  22. """
  23. from sets import Set, ImmutableSet
  24. from compatibility import Incompatible, Older, Newer, Same
  25. from tokenstream import TokenStream
  26. ###
  27. ### Message Template
  28. ###
  29. class Template:
  30.     def __init__(self):
  31.         self.messages = { }
  32.     
  33.     def addMessage(self, m):
  34.         self.messages[m.name] = m
  35.     
  36.     def compatibleWithBase(self, base):
  37.         messagenames = (
  38.               ImmutableSet(self.messages.keys())
  39.             | ImmutableSet(base.messages.keys())
  40.             )
  41.             
  42.         compatibility = Same()
  43.         for name in messagenames:
  44.             selfmessage = self.messages.get(name, None)
  45.             basemessage = base.messages.get(name, None)
  46.             
  47.             if not selfmessage:
  48.                 c = Older("missing message %s, did you mean to deprecate?" % name)
  49.             elif not basemessage:
  50.                 c = Newer("added message %s" % name)
  51.             else:
  52.                 c = selfmessage.compatibleWithBase(basemessage)
  53.                 c.prefix("in message %s: " % name)
  54.             
  55.             compatibility = compatibility.combine(c)
  56.         
  57.         return compatibility
  58. class Message:
  59.     HIGH = "High"
  60.     MEDIUM = "Medium"
  61.     LOW = "Low"
  62.     FIXED = "Fixed"
  63.     priorities = [ HIGH, MEDIUM, LOW, FIXED ]
  64.     prioritieswithnumber = [ FIXED ]
  65.     
  66.     TRUSTED = "Trusted"
  67.     NOTTRUSTED = "NotTrusted"
  68.     trusts = [ TRUSTED, NOTTRUSTED ]
  69.     
  70.     UNENCODED = "Unencoded"
  71.     ZEROCODED = "Zerocoded"
  72.     encodings = [ UNENCODED, ZEROCODED ]
  73.     NOTDEPRECATED = "NotDeprecated"
  74.     DEPRECATED = "Deprecated"
  75.     UDPDEPRECATED = "UDPDeprecated"
  76.     UDPBLACKLISTED = "UDPBlackListed"
  77.     deprecations = [ NOTDEPRECATED, UDPDEPRECATED, UDPBLACKLISTED, DEPRECATED ]
  78.     # in order of increasing deprecation
  79.     
  80.     def __init__(self, name, number, priority, trust, coding):
  81.         self.name = name
  82.         self.number = number
  83.         self.priority = priority
  84.         self.trust = trust
  85.         self.coding = coding
  86.         self.deprecateLevel = 0
  87.         self.blocks = [ ]
  88.     def deprecated(self):
  89.         return self.deprecateLevel != 0
  90.     def deprecate(self, deprecation): 
  91.         self.deprecateLevel = self.deprecations.index(deprecation)
  92.     def addBlock(self, block):
  93.         self.blocks.append(block)
  94.         
  95.     def compatibleWithBase(self, base):
  96.         if self.name != base.name:
  97.             # this should never happen in real life because of the
  98.             # way Template matches up messages by name
  99.             return Incompatible("has different name: %s vs. %s in base"
  100.                                % (self.name, base.name)) 
  101.         if self.priority != base.priority:
  102.             return Incompatible("has different priority: %s vs. %s in base"
  103.                                 % (self.priority, base.priority)) 
  104.         if self.trust != base.trust:
  105.             return Incompatible("has different trust: %s vs. %s in base"
  106.                                 % (self.trust, base.trust)) 
  107.         if self.coding != base.coding:
  108.             return Incompatible("has different coding: %s vs. %s in base"
  109.                                 % (self.coding, base.coding)) 
  110.         if self.number != base.number:
  111.             return Incompatible("has different number: %s vs. %s in base"
  112.                                 % (self.number, base.number))
  113.         
  114.         compatibility = Same()
  115.         if self.deprecateLevel != base.deprecateLevel:
  116.             if self.deprecateLevel < base.deprecateLevel:
  117.                 c = Older("is less deprecated: %s vs. %s in base" % (
  118.                     self.deprecations[self.deprecateLevel],
  119.                     self.deprecations[base.deprecateLevel]))
  120.             else:
  121.                 c = Newer("is more deprecated: %s vs. %s in base" % (
  122.                     self.deprecations[self.deprecateLevel],
  123.                     self.deprecations[base.deprecateLevel]))
  124.             compatibility = compatibility.combine(c)
  125.         
  126.         selflen = len(self.blocks)
  127.         baselen = len(base.blocks)
  128.         samelen = min(selflen, baselen)
  129.             
  130.         for i in xrange(0, samelen):
  131.             selfblock = self.blocks[i]
  132.             baseblock = base.blocks[i]
  133.             
  134.             c = selfblock.compatibleWithBase(baseblock)
  135.             if not c.same():
  136.                 c = Incompatible("block %d isn't identical" % i)
  137.             compatibility = compatibility.combine(c)
  138.         
  139.         if selflen > baselen:
  140.             c = Newer("has %d extra blocks" % (selflen - baselen))
  141.         elif selflen < baselen:
  142.             c = Older("missing %d extra blocks" % (baselen - selflen))
  143.         else:
  144.             c = Same()
  145.         
  146.         compatibility = compatibility.combine(c)
  147.         return compatibility
  148. class Block(object):
  149.     SINGLE = "Single"
  150.     MULTIPLE = "Multiple"
  151.     VARIABLE = "Variable"
  152.     repeats = [ SINGLE, MULTIPLE, VARIABLE ]
  153.     repeatswithcount = [ MULTIPLE ]
  154.     
  155.     def __init__(self, name, repeat, count=None):
  156.         self.name = name
  157.         self.repeat = repeat
  158.         self.count = count
  159.         self.variables = [ ]
  160.     def addVariable(self, variable):
  161.         self.variables.append(variable)
  162.         
  163.     def compatibleWithBase(self, base):
  164.         if self.name != base.name:
  165.             return Incompatible("has different name: %s vs. %s in base"
  166.                                 % (self.name, base.name))
  167.         if self.repeat != base.repeat:
  168.             return Incompatible("has different repeat: %s vs. %s in base"
  169.                                 % (self.repeat, base.repeat))
  170.         if self.repeat in Block.repeatswithcount:
  171.             if self.count != base.count:
  172.                 return Incompatible("has different count: %s vs. %s in base"
  173.                                     % (self.count, base.count)) 
  174.         compatibility = Same()
  175.         
  176.         selflen = len(self.variables)
  177.         baselen = len(base.variables)
  178.         
  179.         for i in xrange(0, min(selflen, baselen)):
  180.             selfvar = self.variables[i]
  181.             basevar = base.variables[i]
  182.             
  183.             c = selfvar.compatibleWithBase(basevar)
  184.             if not c.same():
  185.                 c = Incompatible("variable %d isn't identical" % i)
  186.             compatibility = compatibility.combine(c)
  187.         if selflen > baselen:
  188.             c = Newer("has %d extra variables" % (selflen - baselen))
  189.         elif selflen < baselen:
  190.             c = Older("missing %d extra variables" % (baselen - selflen))
  191.         else:
  192.             c = Same()
  193.         compatibility = compatibility.combine(c)
  194.         return compatibility
  195. class Variable:
  196.     U8 = "U8"; U16 = "U16"; U32 = "U32"; U64 = "U64"
  197.     S8 = "S8"; S16 = "S16"; S32 = "S32"; S64 = "S64"
  198.     F32 = "F32"; F64 = "F64"
  199.     LLVECTOR3 = "LLVector3"; LLVECTOR3D = "LLVector3d"; LLVECTOR4 = "LLVector4"
  200.     LLQUATERNION = "LLQuaternion"
  201.     LLUUID = "LLUUID"
  202.     BOOL = "BOOL"
  203.     IPADDR = "IPADDR"; IPPORT = "IPPORT"
  204.     FIXED = "Fixed"
  205.     VARIABLE = "Variable"
  206.     types = [ U8, U16, U32, U64, S8, S16, S32, S64, F32, F64,
  207.                 LLVECTOR3, LLVECTOR3D, LLVECTOR4, LLQUATERNION,
  208.                 LLUUID, BOOL, IPADDR, IPPORT, FIXED, VARIABLE ]
  209.     typeswithsize = [ FIXED, VARIABLE ]
  210.     
  211.     def __init__(self, name, type, size):
  212.         self.name = name
  213.         self.type = type
  214.         self.size = size
  215.         
  216.     def compatibleWithBase(self, base):
  217.         if self.name != base.name:
  218.             return Incompatible("has different name: %s vs. %s in base"
  219.                                 % (self.name, base.name))
  220.         if self.type != base.type:
  221.             return Incompatible("has different type: %s vs. %s in base"
  222.                                 % (self.type, base.type))
  223.         if self.type in Variable.typeswithsize:
  224.             if self.size != base.size:
  225.                 return Incompatible("has different size: %s vs. %s in base"
  226.                                     % (self.size, base.size)) 
  227.         return Same()
  228. ###
  229. ### Parsing Message Templates
  230. ###
  231. class TemplateParser:
  232.     def __init__(self, tokens):
  233.         self._tokens = tokens
  234.         self._version = 0
  235.         self._numbers = { }
  236.         for p in Message.priorities:
  237.             self._numbers[p] = 0
  238.     def parseTemplate(self):
  239.         tokens = self._tokens
  240.         t = Template()
  241.         while True:
  242.             if tokens.want("version"):
  243.                 v = float(tokens.require(tokens.wantFloat()))
  244.                 self._version = v
  245.                 t.version = v
  246.                 continue
  247.     
  248.             m = self.parseMessage()
  249.             if m:
  250.                 t.addMessage(m)
  251.                 continue
  252.             
  253.             if self._version >= 2.0:
  254.                 tokens.require(tokens.wantEOF())
  255.                 break
  256.             else:
  257.                 if tokens.wantEOF():
  258.                     break
  259.             
  260.                 tokens.consume()
  261.                     # just assume (gulp) that this is a comment
  262.                     # line 468: "sim -> dataserver"
  263.         return t                
  264.     def parseMessage(self):
  265.         tokens = self._tokens
  266.         if not tokens.want("{"):
  267.             return None
  268.         
  269.         name     = tokens.require(tokens.wantSymbol())
  270.         priority = tokens.require(tokens.wantOneOf(Message.priorities))
  271.         
  272.         if self._version >= 2.0  or  priority in Message.prioritieswithnumber:
  273.             number = int("+" + tokens.require(tokens.wantInteger()), 0)
  274.         else:
  275.             self._numbers[priority] += 1
  276.             number = self._numbers[priority]
  277.         
  278.         trust    = tokens.require(tokens.wantOneOf(Message.trusts))
  279.         coding   = tokens.require(tokens.wantOneOf(Message.encodings))
  280.     
  281.         m = Message(name, number, priority, trust, coding)
  282.         
  283.         if self._version >= 2.0:
  284.             d = tokens.wantOneOf(Message.deprecations)
  285.             if d:
  286.                 m.deprecate(d)
  287.                 
  288.         while True:
  289.             b = self.parseBlock()
  290.             if not b:
  291.                 break
  292.             m.addBlock(b)
  293.             
  294.         tokens.require(tokens.want("}"))
  295.         
  296.         return m
  297.     
  298.     
  299.     def parseBlock(self):
  300.         tokens = self._tokens
  301.         if not tokens.want("{"):
  302.             return None
  303.         name = tokens.require(tokens.wantSymbol())
  304.         repeat = tokens.require(tokens.wantOneOf(Block.repeats))
  305.         if repeat in Block.repeatswithcount:
  306.             count = int(tokens.require(tokens.wantInteger()))
  307.         else:
  308.             count = None
  309.     
  310.         b = Block(name, repeat, count)
  311.     
  312.         while True:
  313.             v = self.parseVariable()
  314.             if not v:
  315.                 break
  316.             b.addVariable(v)
  317.             
  318.         tokens.require(tokens.want("}"))
  319.         return b
  320.             
  321.     
  322.     def parseVariable(self):
  323.         tokens = self._tokens
  324.         if not tokens.want("{"):
  325.             return None
  326.         name = tokens.require(tokens.wantSymbol())
  327.         type = tokens.require(tokens.wantOneOf(Variable.types))
  328.         if type in Variable.typeswithsize:
  329.             size = tokens.require(tokens.wantInteger())
  330.         else:
  331.             tokens.wantInteger() # in LandStatRequest: "{ ParcelLocalID S32 1 }" 
  332.             size = None
  333.         tokens.require(tokens.want("}"))
  334.         return Variable(name, type, size)
  335.         
  336. def parseTemplateString(s):
  337.     return TemplateParser(TokenStream().fromString(s)).parseTemplate()
  338. def parseTemplateFile(f):
  339.     return TemplateParser(TokenStream().fromFile(f)).parseTemplate()