Example #1
0
def field_type(type):
    """Extract the outermost type from a field"""
    if not isinstance(type, dict):
        if is_primitive(type):
            return type
        raise CmfParseError(type.parseinfo, f"Invalid field type: {type}")
    # The semantics class puts enum and msg into the same form as a compound
    for compound in [
            "list", "fixedlist", "kvpair", "map", "optional", "oneof", "enum",
            "msg"
    ]:
        if compound in type:
            return compound
    raise CmfParseError(type.parseinfo, f"Invalid field type: {type}")
Example #2
0
 def enumname(self, ast):
     """ Check that enum names are unique """
     if ast.name in self.symbol_table.enum_names:
         raise CmfParseError(
             ast.parseinfo, 'Enum: "{}" already defined on line {}'.format(
                 ast.name, self.symbol_table.enum_names[ast.name]))
     if ast.name in self.symbol_table.msg_names:
         raise CmfParseError(
             ast.parseinfo,
             'Enum: "{}" cannot have the same name as the Msg defined on line {}'
             .format(ast.name, self.symbol_table.msg_names[ast.name]))
     # parseinfo.line is zero-based
     self.symbol_table.enum_names[ast.name] = ast.parseinfo.line + 1
     return ast.name
Example #3
0
 def msgid(self, ast):
     """ Check that each message id is unique and fits in a 32 bit integer """
     id = int(ast.id)
     if id < 0 or id > pow(2, 32):
         raise CmfParseError(
             ast.parseinfo,
             'Message ID: "{}" must fit in a uint32'.format(id))
     if id in self.symbol_table.msg_ids:
         raise CmfParseError(
             ast.parseinfo,
             'Message ID: "{}" already defined on line {}'.format(
                 id, self.symbol_table.msg_ids[id]))
     # parseinfo.line is zero-based
     self.symbol_table.msg_ids[id] = ast.parseinfo.line + 1
     return id
Example #4
0
 def msgname_ref(self, ast):
     if ast.name not in self.symbol_table.msg_names.keys():
         raise CmfParseError(
             ast.parseinfo,
             "Messages must be defined before they are referenced: {}".
             format(ast.name))
     return ast.name
Example #5
0
 def enum_def(self, ast):
     """ Ensure that an enum fits in a uint8 and that it has no duplicate fields """
     if (len(ast.tags) > 256):
         raise CmfParseError(
             ast.parseinfo,
             'Enum: "{}" contains more than 256 entries. It must fit in a uint8_t'
             .format(ast.name))
     tags = set()
     for tag in ast.tags:
         if tag in tags:
             raise CmfParseError(
                 ast.parseinfo,
                 'Enum: "{}" contains duplicate tag: "{}"'.format(
                     ast.name, tag))
         tags.add(tag)
     return ast
Example #6
0
 def walk_type(self, type):
     if not isinstance(type, dict):
         if is_primitive(type):
             getattr(self.visitor, type)()
         else:
             self.visitor.msgname_ref(type)
     elif "list" in type:
         self.visitor.list_start()
         self.walk_type(type.list.type)
         self.visitor.list_end()
     elif "kvpair" in type:
         self.visitor.kvpair_start()
         self.walk_type(type.kvpair.key)
         self.visitor.kvpair_key_end()
         self.walk_type(type.kvpair.value)
         self.visitor.kvpair_end()
     elif "map" in type:
         self.visitor.map_start()
         self.walk_type(type.map.key)
         self.visitor.map_key_end()
         self.walk_type(type.map.value)
         self.visitor.map_end()
     elif "optional" in type:
         self.visitor.optional_start()
         self.walk_type(type.optional.type)
         self.visitor.optional_end()
     elif "oneof" in type:
         self.visitor.oneof(
             dict([(n, self.msgs[n]) for n in type.oneof.msg_names]))
     else:
         raise CmfParseError(type.parseinfo, "Invalid field type")
Example #7
0
 def walk_type(self, type):
     if not isinstance(type, dict):
         if is_primitive(type):
             getattr(self.visitor, type)()
     elif "list" in type:
         self.visitor.list_start()
         self.walk_type(type.list.type)
         self.visitor.list_end()
     elif "fixedlist" in type:
         self.visitor.fixedlist_start()
         self.walk_type(type.fixedlist.type)
         self.visitor.fixedlist_type_end()
         self.visitor.fixedlist_end(type.fixedlist.size)
     elif "kvpair" in type:
         self.visitor.kvpair_start()
         self.walk_type(type.kvpair.key)
         self.visitor.kvpair_key_end()
         self.walk_type(type.kvpair.value)
         self.visitor.kvpair_end()
     elif "map" in type:
         self.visitor.map_start()
         self.walk_type(type.map.key)
         self.visitor.map_key_end()
         self.walk_type(type.map.value)
         self.visitor.map_end()
     elif "optional" in type:
         self.visitor.optional_start()
         self.walk_type(type.optional.type)
         self.visitor.optional_end()
     elif "oneof" in type:
         msgs = dict()
         for d in type.oneof.msg_names:
             if not 'msg' in d:
                 # This is needed to prevent oneofs of Enums now that both messages and enums
                 # are top level types
                 raise CmfParseError(
                     type.parseinfo,
                     "A oneof can only contain names of messages")
             name = d['msg']
             msgs[name] = self.msgs[name]
         self.visitor.oneof(msgs)
     elif "msg" in type:
         self.visitor.msgname_ref(type['msg'])
     elif "enum" in type:
         self.visitor.enum(type['enum'])
     else:
         raise CmfParseError(type.parseinfo, "Invalid field type")
Example #8
0
 def msgname(self, ast):
     """ Check that message names are unique """
     if ast.name in self.symbol_table.msg_names:
         raise CmfParseError(
             ast.parseinfo,
             'Message: "{}" already defined on line {}'.format(
                 ast.name, self.symbol_table.msg_names[ast.name]))
     # parseinfo.line is zero-based
     self.symbol_table.msg_names[ast.name] = ast.parseinfo.line + 1
     return ast.name
Example #9
0
 def toplevel_ref(self, ast):
     """ Determine if the name in the ast is a Msg or Enum and tag it. """
     if ast.name in self.symbol_table.msg_names.keys():
         return {'msg': ast.name}
     if ast.name in self.symbol_table.enum_names.keys():
         return {'enum': ast.name}
     raise CmfParseError(
         ast.parseinfo,
         "Messages or Enums must be defined before they are referenced: {}".
         format(ast.name))
Example #10
0
def field_type(type):
    """Extract the outermost type from a field"""
    if not isinstance(type, dict):
        if is_primitive(type):
            return type
        return "msg"
    for compound in ["list", "kvpair", "map", "optional", "oneof"]:
        if compound in type:
            return compound
    raise CmfParseError(type.parseinfo, f"Invalid field type: {type}")
Example #11
0
 def msg(self, ast):
     """ Check that each field in a message has a unique name """
     field_names = set()
     for field in ast.fields:
         if field.name in field_names:
             raise CmfParseError(
                 ast.parseinfo,
                 'Message: "{}" contains duplicate field: "{}"'.format(
                     ast.name, field.name))
         field_names.add(field.name)
     return ast