Exemple #1
0
    def __init__(self,
                 enums_dict=None,
                 consts_dict=None,
                 typedefs_dict=None,
                 hints_dict=None,
                 structs_dict=None,
                 funcs_dict=None,
                 strings_dict=None,
                 func_ptrs_dict=None,
                 index_dict=None):
        """Constructs a new HeaderParser instance.

    The optional arguments listed below can be used to passing in dict-like
    objects specifying pre-defined declarations. By default empty
    UniqueOrderedDicts will be instantiated and then populated according to the
    contents of the headers.

    Args:
      enums_dict: nested mappings from {enum_name: {member_name: value}}
      consts_dict: mapping from {const_name: value}
      typedefs_dict: mapping from {type_name: ctypes_typename}
      hints_dict: mapping from {var_name: shape_tuple}
      structs_dict: mapping from {struct_name: Struct_instance}
      funcs_dict: mapping from {func_name: Function_instance}
      strings_dict: mapping from {var_name: StaticStringArray_instance}
      func_ptrs_dict: mapping from {var_name: FunctionPtr_instance}
      index_dict: mapping from {lowercase_struct_name: {var_name: shape_tuple}}
    """
        self.enums_dict = (enums_dict if enums_dict is not None else
                           codegen_util.UniqueOrderedDict())
        self.consts_dict = (consts_dict if consts_dict is not None else
                            codegen_util.UniqueOrderedDict())
        self.typedefs_dict = (typedefs_dict if typedefs_dict is not None else
                              codegen_util.UniqueOrderedDict())
        self.hints_dict = (hints_dict if hints_dict is not None else
                           codegen_util.UniqueOrderedDict())
        self.structs_dict = (structs_dict if structs_dict is not None else
                             codegen_util.UniqueOrderedDict())
        self.funcs_dict = (funcs_dict if funcs_dict is not None else
                           codegen_util.UniqueOrderedDict())
        self.strings_dict = (strings_dict if strings_dict is not None else
                             codegen_util.UniqueOrderedDict())
        self.func_ptrs_dict = (func_ptrs_dict if func_ptrs_dict is not None
                               else codegen_util.UniqueOrderedDict())
        self.index_dict = (index_dict if index_dict is not None else
                           codegen_util.UniqueOrderedDict())
Exemple #2
0
 def parse_functions(self, src):
     """Updates self.funcs_dict."""
     parser = header_parsing.MJAPI_FUNCTION_DECL
     for tokens, _, _ in parser.scanString(src):
         for token in tokens:
             name = codegen_util.mangle_varname(token.name)
             comment = codegen_util.mangle_comment(token.comment)
             args = codegen_util.UniqueOrderedDict()
             for arg in token.arguments:
                 a = self.get_type_from_token(arg)
                 args[a.name] = a
             r = self.get_type_from_token(token.return_value)
             f = c_declarations.Function(name, args, r, comment)
             self.funcs_dict[f.name] = f
Exemple #3
0
 def parse_enums(self, src):
   """Parses mj*.h, update self.enums_dict."""
   parser = header_parsing.ENUM_DECL
   for tokens, _, _ in parser.scanString(src):
     for enum in tokens:
       members = codegen_util.UniqueOrderedDict()
       value = 0
       for member in enum.members:
         # Leftward bitshift
         if member.bit_lshift_a:
           value = int(member.bit_lshift_a) << int(member.bit_lshift_b)
         # Assignment
         elif member.value:
           value = int(member.value)
         # Implicit count
         else:
           value += 1
         members.update({member.name: value})
       self.enums_dict.update({enum.name: members})
Exemple #4
0
    def get_type_from_token(self, token, parent=None):
        """Accepts a token returned by a parser, returns a subclass of CDeclBase."""

        comment = codegen_util.mangle_comment(token.comment)
        is_const = token.is_const == "const"

        # A new struct declaration
        if token.members:

            name = token.name

            # If the name is empty, see if there is a type declaration that matches
            # this struct's typename
            if not name:
                for k, v in six.iteritems(self.typedefs_dict):
                    if v == token.typename:
                        name = k

            # Anonymous structs need a dummy typename
            typename = token.typename
            if not typename:
                if parent:
                    typename = token.name
                else:
                    raise Error(
                        "Anonymous structs that aren't members of a named struct are not "
                        "supported (name = '{token.name}').".format(
                            token=token))

            # Mangle the name if it contains any protected keywords
            name = codegen_util.mangle_varname(name)

            members = codegen_util.UniqueOrderedDict()
            sub_structs = codegen_util.UniqueOrderedDict()
            out = c_declarations.Struct(name, typename, members, sub_structs,
                                        comment, parent, is_const)

            # Map the old typename to the mangled typename in typedefs_dict
            self.typedefs_dict[typename] = out.ctypes_typename

            # Add members
            for sub_token in token.members:

                # Recurse into nested structs
                member = self.get_type_from_token(sub_token, parent=out)
                out.members[member.name] = member

                # Nested sub-structures need special treatment
                if isinstance(member, c_declarations.Struct):
                    out.sub_structs[member.name] = member

            # Add to dict of structs
            self.structs_dict[out.ctypes_typename] = out

        else:

            name = codegen_util.mangle_varname(token.name)
            typename = self.resolve_typename(token.typename)

            # 1D array with size defined at compile time
            if token.size:
                shape = self.get_shape_tuple(token.size)
                if typename in header_parsing.CTYPES_TO_NUMPY:
                    out = c_declarations.StaticNDArray(name, typename, shape,
                                                       comment, parent,
                                                       is_const)
                else:
                    out = c_declarations.StaticPtrArray(
                        name, typename, shape, comment, parent, is_const)
            elif token.ptr:

                # Pointer to a numpy-compatible type, could be an array or a scalar
                if typename in header_parsing.CTYPES_TO_NUMPY:

                    # Multidimensional array (one or more dimensions might be undefined)
                    if name in self.hints_dict:

                        # Dynamically-sized dimensions have string identifiers
                        shape = self.hints_dict[name]
                        if any(isinstance(d, str) for d in shape):
                            out = c_declarations.DynamicNDArray(
                                name, typename, shape, comment, parent,
                                is_const)
                        else:
                            out = c_declarations.StaticNDArray(
                                name, typename, shape, comment, parent,
                                is_const)

                    # This must be a pointer to a scalar primitive
                    else:
                        out = c_declarations.ScalarPrimitivePtr(
                            name, typename, comment, parent, is_const)

                # Pointer to struct or other arbitrary type
                else:
                    out = c_declarations.ScalarPrimitivePtr(
                        name, typename, comment, parent, is_const)

            # A struct we've already encountered
            elif typename in self.structs_dict:
                s = self.structs_dict[typename]
                out = c_declarations.Struct(name, s.typename, s.members,
                                            s.sub_structs, comment, parent)

            # Presumably this is a scalar primitive
            else:
                out = c_declarations.ScalarPrimitive(name, typename, comment,
                                                     parent, is_const)

        return out
Exemple #5
0
def main(unused_argv):
  special_header_paths = {}

  # Get the path to the mjmodel and mjxmacro header files.
  # These header files need special handling.
  for header in (_MJMODEL_H, _MJXMACRO_H):
    for path in FLAGS.header_paths:
      if path.endswith(header):
        special_header_paths[header] = path
        break
    if header not in special_header_paths:
      logging.fatal("List of inputs must contain a path to %s", header)

  # Make sure mjmodel.h is parsed first, since it is included by other headers.
  srcs = codegen_util.UniqueOrderedDict()
  sorted_header_paths = sorted(FLAGS.header_paths)
  sorted_header_paths.remove(special_header_paths[_MJMODEL_H])
  sorted_header_paths.insert(0, special_header_paths[_MJMODEL_H])
  for p in sorted_header_paths:
    with io.open(p, "r", errors="ignore") as f:
      srcs[p] = f.read()

  # consts_dict should be a codegen_util.UniqueOrderedDict.
  # This is a temporary workaround due to the fact that the parser does not yet
  # handle nested `#if define(predicate)` blocks, which results in some
  # constants being parsed twice. We therefore can't enforce the uniqueness of
  # the keys in `consts_dict`. As of MuJoCo v1.30 there is only a single problem
  # block beginning on line 10 in mujoco.h, and a single constant is affected
  # (MJAPI).
  consts_dict = collections.OrderedDict()

  # These are commented in `mjdata.h` but have no macros in `mjxmacro.h`.
  hints_dict = codegen_util.UniqueOrderedDict({"buffer": ("nbuffer",),
                                               "stack": ("nstack",)})

  parser = binding_generator.BindingGenerator(
      consts_dict=consts_dict, hints_dict=hints_dict)

  # Parse enums.
  for pth, src in six.iteritems(srcs):
    if pth is not special_header_paths[_MJXMACRO_H]:
      parser.parse_enums(src)

  # Parse constants and type declarations.
  for pth, src in six.iteritems(srcs):
    if pth is not special_header_paths[_MJXMACRO_H]:
      parser.parse_consts_typedefs(src)

  # Get shape hints from mjxmacro.h.
  parser.parse_hints(srcs[special_header_paths[_MJXMACRO_H]])

  # Parse structs and function pointer type declarations.
  for pth, src in six.iteritems(srcs):
    if pth is not special_header_paths[_MJXMACRO_H]:
      parser.parse_structs_and_function_pointer_typedefs(src)

  # Parse functions.
  for pth, src in six.iteritems(srcs):
    if pth is not special_header_paths[_MJXMACRO_H]:
      parser.parse_functions(src)

  # Parse global strings and function pointers.
  for pth, src in six.iteritems(srcs):
    if pth is not special_header_paths[_MJXMACRO_H]:
      parser.parse_global_strings(src)
      parser.parse_function_pointers(src)

  # Create the output directory if it doesn't already exist.
  if not os.path.exists(FLAGS.output_dir):
    os.makedirs(FLAGS.output_dir)

  # Generate Python source files and write them to the output directory.
  parser.write_consts(os.path.join(FLAGS.output_dir, "constants.py"))
  parser.write_enums(os.path.join(FLAGS.output_dir, "enums.py"))
  parser.write_types(os.path.join(FLAGS.output_dir, "types.py"))
  parser.write_wrappers(os.path.join(FLAGS.output_dir, "wrappers.py"))
  parser.write_funcs_and_globals(os.path.join(FLAGS.output_dir, "functions.py"))
  parser.write_index_dict(os.path.join(FLAGS.output_dir, "sizes.py"))
def main(unused_argv):
    # Get the path to the xmacro header file.
    xmacro_hdr_path = None
    for path in FLAGS.header_paths:
        if path.endswith("mjxmacro.h"):
            xmacro_hdr_path = path
            break
    if xmacro_hdr_path is None:
        logging.fatal("List of inputs must contain a path to mjxmacro.h")

    srcs = codegen_util.UniqueOrderedDict()
    for p in sorted(FLAGS.header_paths):
        with open(p, "r") as f:
            srcs[p] = f.read()

    # consts_dict should be a codegen_util.UniqueOrderedDict.
    # This is a temporary workaround due to the fact that the parser does not yet
    # handle nested `#if define(predicate)` blocks, which results in some
    # constants being parsed twice. We therefore can't enforce the uniqueness of
    # the keys in `consts_dict`. As of MuJoCo v1.30 there is only a single problem
    # block beginning on line 10 in mujoco.h, and a single constant is affected
    # (MJAPI).
    consts_dict = collections.OrderedDict()

    # These are commented in `mjdata.h` but have no macros in `mjxmacro.h`.
    hints_dict = codegen_util.UniqueOrderedDict({
        "buffer": ("nbuffer", ),
        "stack": ("nstack", )
    })

    parser = binding_generator.BindingGenerator(consts_dict=consts_dict,
                                                hints_dict=hints_dict)

    # Parse enums.
    for pth, src in six.iteritems(srcs):
        if pth is not xmacro_hdr_path:
            parser.parse_enums(src)

    # Parse constants and type declarations.
    for pth, src in six.iteritems(srcs):
        if pth is not xmacro_hdr_path:
            parser.parse_consts_typedefs(src)

    # Get shape hints from mjxmacro.h.
    parser.parse_hints(srcs[xmacro_hdr_path])

    # Parse structs.
    for pth, src in six.iteritems(srcs):
        if pth is not xmacro_hdr_path:
            parser.parse_structs(src)

    # Parse functions.
    for pth, src in six.iteritems(srcs):
        if pth is not xmacro_hdr_path:
            parser.parse_functions(src)

    # Parse global strings and function pointers.
    for pth, src in six.iteritems(srcs):
        if pth is not xmacro_hdr_path:
            parser.parse_global_strings(src)
            parser.parse_function_pointers(src)

    # Create the output directory if it doesn't already exist.
    if not os.path.exists(FLAGS.output_dir):
        os.makedirs(FLAGS.output_dir)

    # Generate Python source files and write them to the output directory.
    parser.write_consts(os.path.join(FLAGS.output_dir, "constants.py"))
    parser.write_enums(os.path.join(FLAGS.output_dir, "enums.py"))
    parser.write_types(os.path.join(FLAGS.output_dir, "types.py"))
    parser.write_wrappers(os.path.join(FLAGS.output_dir, "wrappers.py"))
    parser.write_funcs_and_globals(
        os.path.join(FLAGS.output_dir, "functions.py"))
    parser.write_index_dict(os.path.join(FLAGS.output_dir, "sizes.py"))