Source code for rocon_uri.rules

#
# License: BSD
#   https://raw.github.com/robotics-in-concert/rocon_tools/license/LICENSE
#
##############################################################################
# Description
##############################################################################

"""
.. module:: rules
   :platform: Unix
   :synopsis: EBNF rules used in parsing rocon_uri strings.

This module defines `ebnf rules`_ used in parsing rocon_uri strings. It should
never be used directly, it is the engine for the core parsing and
manipulation module.

.. _`ebnf rules`: http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form

----

"""

##############################################################################
# Imports
##############################################################################

import os
import yaml

# Local imports

##############################################################################
# Rules
##############################################################################


[docs]def load_rules_into_dictionary(): """ Load the rules in rocon_uri/src/rocon_uri/rules/rules.yaml into a python dictionary object. :returns: python dictionary of rules loaded from yaml. :rtype: str """ yaml_filename = os.path.join(os.path.dirname(__file__), 'rules', 'rules.yaml') with open(yaml_filename) as f: yaml_rules = yaml.load(f) return yaml_rules
[docs]def walk_yaml_rules(name, root=None): ''' A generator which walks through the yaml list of rules. Works in almost exactly the same way as os.path.walk. If a root for a ebnf rules dictionary is not specified, it will load the default rules dictionary, see :func:`.load_rules_into_dictionary`. Usage::: for name, group, elements in walk_yaml('hardware_platform', yaml_rules['hardware_platform']): print("Name: %s" % name) print(" Group: %s" % group) print(" Elements: %s" % elements) :param name: a name to attach to the current 3-tuple that gets yielded by the generator. :type name: str :param root: a python dictionary representing the root of an object loaded from a yaml rules file :type root: dict ''' #print("Walking %s" % name) if root is None: root = load_rules_into_dictionary() groups = {} elements = [] for element in root: if isinstance(element, dict): groups.update(element) else: elements.append(element) # Make sure the elements are in reverse order so when ebnf rule matching happens # turtlebot2 tries to match before turtlebot # https://github.com/robotics-in-concert/rocon_tools/issues/17 elements.sort(reverse=True) #print(" Groups: %s" % groups.keys()) #print(" Elements: %s" % elements) yield (name, groups.keys(), elements) if not groups.keys(): return for key, value in groups.iteritems(): for x in walk_yaml_rules(name + '/' + key, value): yield x return
[docs]def load_ebnf_rules(): """ Load our rules from yaml and construct an `ebnf <http://wiki.ros.org/rocon_ebnf>`_ rules dictionary for parsing rocon uri strings. :returns: python dictionary of rules loaded from yaml. :rtype: str """ yaml_rule_sets = {} yaml_rules = load_rules_into_dictionary() for yaml_rule_set in yaml_rules: # merge each of hardware_platform, application_framework, os into one dictionary yaml_rule_sets.update(yaml_rule_set) # special case, add the names as an empty list yaml_rule_sets['name'] = [] for yaml_rule_set_name, yaml_rule_set in yaml_rule_sets.iteritems(): rules = [] #rules.append('option verbose') rules.append('init %s_list=[]' % yaml_rule_set_name) rules.append('pattern ::= zero element*') rules.append('zero ::= %s @%s_list.append("$%s")' % (yaml_rule_set_name, yaml_rule_set_name, yaml_rule_set_name)) rules.append('element ::= "|" %s @%s_list.append("$%s")' % (yaml_rule_set_name, yaml_rule_set_name, yaml_rule_set_name)) for name, groups, elements in walk_yaml_rules(yaml_rule_set_name, yaml_rule_set): # Accept a wildcard for each rule = '%s ::= "*"' % name.split('/')[-1] element_rules = ' | '.join(['"%s"' % element for element in elements]) group_rules = ' | '.join(groups) if groups: rule += " | " + group_rules if elements: rule += " | " + element_rules # special case - let anything through for names. if yaml_rule_set_name == "name": rule += ' | r"\S"*' rules.append(rule) yaml_rule_sets[yaml_rule_set_name] = rules return yaml_rule_sets