/pyang/syntax.py
Python | 259 lines | 213 code | 18 blank | 28 comment | 9 complexity | 7422b1266e8b36743d15891154d7456f MD5 | raw file
Possible License(s): 0BSD
- """Description of YANG & YIN syntax."""
- import re
- ### Regular expressions - constraints on arguments
- # keywords and identifiers
- identifier = r"[_A-Za-z][._\-A-Za-z0-9]*"
- prefix = identifier
- keyword = '((' + prefix + '):)?(' + identifier + ')'
- # no group version of keyword
- keyword_ng = '(?:(' + prefix + '):)?(?:' + identifier + ')'
- re_keyword = re.compile(keyword)
- re_keyword_start = re.compile('^' + keyword)
- pos_integer = r"[1-9][0-9]*"
- nonneg_integer = r"(0|[1-9])[0-9]*"
- integer_ = r"[-+]?" + nonneg_integer
- decimal_ = r"(\+|\-)?[0-9]+(\.[0-9]+)?"
- length_str = '((min|max|[0-9]+)\s*' \
- '(\.\.\s*' \
- '(min|max|[0-9]+)\s*)?)'
- length_expr = length_str + '(\|\s*' + length_str + ')*'
- re_length_part = re.compile(length_str)
- range_str = '((\-INF|min|max|((\+|\-)?[0-9]+(\.[0-9]+)?))\s*' \
- '(\.\.\s*' \
- '(INF|min|max|(\+|\-)?[0-9]+(\.[0-9]+)?)\s*)?)'
- range_expr = range_str + '(\|\s*' + range_str + ')*'
- re_range_part = re.compile(range_str)
- re_identifier = re.compile("^" + identifier + "$")
- # path and unique
- node_id = keyword_ng
- rel_path_keyexpr = r"(\.\./)+(" + node_id + "/)*" + node_id
- path_key_expr = r"(current\s*\(\s*\)/" + rel_path_keyexpr + ")"
- path_equality_expr = node_id + r"\s*=\s*" + path_key_expr
- path_predicate = r"\s*\[\s*" + path_equality_expr + r"\s*\]\s*"
- absolute_path_arg = "(?:/" + node_id + "(" + path_predicate + ")*)+"
- descendant_path_arg = node_id + "(" + path_predicate + ")*" + \
- "(?:" + absolute_path_arg + ")?"
- relative_path_arg = r"(\.\./)*" + descendant_path_arg
- deref_path_arg = r"deref\s*\(\s*(?:" + relative_path_arg + ")\s*\)/\.\./" + relative_path_arg
- path_arg = "(" + absolute_path_arg + "|" + relative_path_arg + "|" + \
- deref_path_arg + ")"
- absolute_schema_nodeid = "(/" + node_id + ")+"
- descendant_schema_nodeid = node_id + "(" + absolute_schema_nodeid + ")?"
- schema_nodeid = "("+absolute_schema_nodeid+"|"+descendant_schema_nodeid+")"
- unique_arg = descendant_schema_nodeid + "(\s+" + descendant_schema_nodeid + ")*"
- key_arg = node_id + "(\s+" + node_id + ")*"
- re_schema_node_id_part = re.compile('/' + keyword)
- # URI - RFC 3986, Appendix A
- scheme = "[A-Za-z][-+.A-Za-z0-9]*"
- unreserved = "[-._~A-Za-z0-9]"
- pct_encoded = "%[0-9A-F]{2}"
- sub_delims = "[!$&'()*+,;=]"
- pchar = ("(" + unreserved + "|" + pct_encoded + "|" +
- sub_delims + "|[:@])")
- segment = pchar + "*"
- segment_nz = pchar + "+"
- userinfo = ("(" + unreserved + "|" + pct_encoded + "|" +
- sub_delims + "|:)*")
- dec_octet = "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"
- ipv4address = "(" + dec_octet + r"\.){3}" + dec_octet
- h16 = "[0-9A-F]{1,4}"
- ls32 = "(" + h16 + ":" + h16 + "|" + ipv4address + ")"
- ipv6address = (
- "((" + h16 + ":){6}" + ls32 +
- "|::(" + h16 + ":){5}" + ls32 +
- "|(" + h16 + ")?::(" + h16 + ":){4}" + ls32 +
- "|((" + h16 + ":)?" + h16 + ")?::(" + h16 + ":){3}" + ls32 +
- "|((" + h16 + ":){,2}" + h16 + ")?::(" + h16 + ":){2}" + ls32 +
- "|((" + h16 + ":){,3}" + h16 + ")?::" + h16 + ":" + ls32 +
- "|((" + h16 + ":){,4}" + h16 + ")?::" + ls32 +
- "|((" + h16 + ":){,5}" + h16 + ")?::" + h16 +
- "|((" + h16 + ":){,6}" + h16 + ")?::)")
- ipvfuture = r"v[0-9A-F]+\.(" + unreserved + "|" + sub_delims + "|:)+"
- ip_literal = r"\[(" + ipv6address + "|" + ipvfuture + r")\]"
- reg_name = "(" + unreserved + "|" + pct_encoded + "|" + sub_delims + ")*"
- host = "(" + ip_literal + "|" + ipv4address + "|" + reg_name + ")"
- port = "[0-9]*"
- authority = "(" + userinfo + "@)?" + host + "(:" + port + ")?"
- path_abempty = "(/" + segment + ")*"
- path_absolute = "/(" + segment_nz + "(/" + segment + ")*)?"
- path_rootless = segment_nz + "(/" + segment + ")*"
- path_empty = pchar + "{0}"
- hier_part = ("(" + "//" + authority + path_abempty + "|" +
- path_absolute + "|" + path_rootless + "|" + path_empty + ")")
- query = "(" + pchar + "|[/?])*"
- fragment = query
- uri = (scheme + ":" + hier_part + r"(\?" + query + ")?" +
- "(#" + fragment + ")?")
- # Date
- date = r"[1-2][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"
- re_nonneg_integer = re.compile("^" + nonneg_integer + "$")
- re_integer = re.compile("^" + integer_ + "$")
- re_decimal = re.compile("^" + decimal_ + "$")
- re_uri = re.compile("^" + uri + "$")
- re_boolean = re.compile("^(true|false)$")
- re_version = re.compile("^1$")
- re_date = re.compile("^" + date +"$")
- re_status = re.compile("^(current|obsolete|deprecated)$")
- re_key = re.compile("^" + key_arg + "$")
- re_length = re.compile("^" + length_expr + "$")
- re_range = re.compile("^" + range_expr + "$")
- re_pos_integer = re.compile(r"^(unbounded|" + pos_integer + r")$")
- re_ordered_by = re.compile(r"^(user|system)$")
- re_node_id = re.compile("^" + node_id + "$")
- re_path = re.compile("^" + path_arg + "$")
- re_absolute_path = re.compile("^" + absolute_path_arg + "$")
- re_unique = re.compile("^" + unique_arg + "$")
- re_schema_nodeid = re.compile("^" + schema_nodeid + "$")
- re_absolute_schema_nodeid = re.compile("^" + absolute_schema_nodeid + "$")
- re_descendant_schema_nodeid = re.compile("^" + descendant_schema_nodeid + "$")
- re_deviate = re.compile("^(add|delete|replace|not-supported)$")
- arg_type_map = {
- "identifier": lambda s: re_identifier.search(s) is not None,
- "non-negative-integer": lambda s: re_nonneg_integer.search(s) is not None,
- "integer": lambda s: re_integer.search(s) is not None,
- "uri": lambda s: re_uri.search(s) is not None,
- "boolean": lambda s: re_boolean.search(s) is not None,
- "version": lambda s: re_version.search(s) is not None,
- "date": lambda s: re_date.search(s) is not None,
- "status-arg": lambda s: re_status.search(s) is not None,
- "key-arg": lambda s: re_key.search(s) is not None,
- "length-arg": lambda s: re_length.search(s) is not None,
- "range-arg": lambda s: re_range.search(s) is not None,
- "max-value": lambda s: re_pos_integer.search(s) is not None,
- "ordered-by-arg": lambda s: re_ordered_by.search(s) is not None,
- "identifier-ref": lambda s: re_node_id.search(s) is not None,
- "path-arg": lambda s: re_path.search(s) is not None,
- "absolute-path-arg": lambda s: re_absolute_path.search(s) is not None,
- "unique-arg": lambda s: re_unique.search(s) is not None,
- "absolute-schema-nodeid": lambda s: \
- re_absolute_schema_nodeid.search(s) is not None,
- "descendant-schema-nodeid": lambda s: \
- re_descendant_schema_nodeid.search(s) is not None,
- "schema-nodeid": lambda s: \
- re_schema_nodeid.search(s) is not None,
- "enum-arg": lambda s: chk_enum_arg(s),
- "fraction-digits-arg": lambda s: chk_fraction_digits_arg(s),
- "deviate-arg": lambda s: re_deviate.search(s) is not None,
- }
- """Argument type definitions.
- Regular expressions for all argument types except plain string that
- are checked directly by the parser.
- """
- def chk_enum_arg(s):
- """Checks if the string `s` is a valid enum string.
- Return True or False."""
- if len(s) == 0 or s[0].isspace() or s[-1].isspace():
- return False
- else:
- return True
- def chk_fraction_digits_arg(s):
- """Checks if the string `s` is a valid fraction-digits argument.
- Return True or False."""
- try:
- v = int(s)
- if v >= 1 and v <= 18:
- return True
- else:
- return False
- except ValueError:
- return False
-
- def add_arg_type(arg_type, regexp):
- """Add a new arg_type to the map.
- Used by extension plugins to register their own argument types."""
- arg_type_map[arg_type] = regexp
- # keyword argument-name yin-element
- yin_map = \
- {'anyxml': ('name', False),
- 'argument': ('name', False),
- 'augment': ('target-node', False),
- 'base': ('name', False),
- 'belongs-to': ('module', False),
- 'bit': ('name', False),
- 'case': ('name', False),
- 'choice': ('name', False),
- 'config': ('value', False),
- 'contact': ('text', True),
- 'container': ('name', False),
- 'default': ('value', False),
- 'description': ('text', True),
- 'deviate': ('value', False),
- 'deviation': ('target-node', False),
- 'enum': ('name', False),
- 'error-app-tag': ('value', False),
- 'error-message': ('value', True),
- 'extension': ('name', False),
- 'feature': ('name', False),
- 'fraction-digits': ('value', False),
- 'grouping': ('name', False),
- 'identity': ('name', False),
- 'if-feature': ('name', False),
- 'import': ('module', False),
- 'include': ('module', False),
- 'input': (None, None),
- 'key': ('value', False),
- 'leaf': ('name', False),
- 'leaf-list': ('name', False),
- 'length': ('value', False),
- 'list': ('name', False),
- 'mandatory': ('value', False),
- 'max-elements': ('value', False),
- 'min-elements': ('value', False),
- 'module': ('name', False),
- 'must': ('condition', False),
- 'namespace': ('uri', False),
- 'notification': ('name', False),
- 'ordered-by': ('value', False),
- 'organization': ('text', True),
- 'output': (None, None),
- 'path': ('value', False),
- 'pattern': ('value', False),
- 'position': ('value', False),
- 'presence': ('value', False),
- 'prefix': ('value', False),
- 'range': ('value', False),
- 'reference': ('text', True),
- 'refine': ('target-node', False),
- 'require-instance': ('value', False),
- 'revision': ('date', False),
- 'revision-date': ('date', False),
- 'rpc': ('name', False),
- 'status': ('value', False),
- 'submodule': ('name', False),
- 'type': ('name', False),
- 'typedef': ('name', False),
- 'unique': ('tag', False),
- 'units': ('name', False),
- 'uses': ('name', False),
- 'value': ('value', False),
- 'when': ('condition', False),
- 'yang-version': ('value', False),
- 'yin-element': ('value', False),
- }
- """Mapping of statements to the YIN representation of their arguments.
- The values are pairs whose first component specifies whether the
- argument is stored in a subelement and the second component is the
- name of the attribute or subelement carrying the argument. See YANG
- specification.
- """