PageRenderTime 90ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/pyang/syntax.py

http://pyang.googlecode.com/
Python | 259 lines | 213 code | 18 blank | 28 comment | 9 complexity | 7422b1266e8b36743d15891154d7456f MD5 | raw file
Possible License(s): 0BSD
  1. """Description of YANG & YIN syntax."""
  2. import re
  3. ### Regular expressions - constraints on arguments
  4. # keywords and identifiers
  5. identifier = r"[_A-Za-z][._\-A-Za-z0-9]*"
  6. prefix = identifier
  7. keyword = '((' + prefix + '):)?(' + identifier + ')'
  8. # no group version of keyword
  9. keyword_ng = '(?:(' + prefix + '):)?(?:' + identifier + ')'
  10. re_keyword = re.compile(keyword)
  11. re_keyword_start = re.compile('^' + keyword)
  12. pos_integer = r"[1-9][0-9]*"
  13. nonneg_integer = r"(0|[1-9])[0-9]*"
  14. integer_ = r"[-+]?" + nonneg_integer
  15. decimal_ = r"(\+|\-)?[0-9]+(\.[0-9]+)?"
  16. length_str = '((min|max|[0-9]+)\s*' \
  17. '(\.\.\s*' \
  18. '(min|max|[0-9]+)\s*)?)'
  19. length_expr = length_str + '(\|\s*' + length_str + ')*'
  20. re_length_part = re.compile(length_str)
  21. range_str = '((\-INF|min|max|((\+|\-)?[0-9]+(\.[0-9]+)?))\s*' \
  22. '(\.\.\s*' \
  23. '(INF|min|max|(\+|\-)?[0-9]+(\.[0-9]+)?)\s*)?)'
  24. range_expr = range_str + '(\|\s*' + range_str + ')*'
  25. re_range_part = re.compile(range_str)
  26. re_identifier = re.compile("^" + identifier + "$")
  27. # path and unique
  28. node_id = keyword_ng
  29. rel_path_keyexpr = r"(\.\./)+(" + node_id + "/)*" + node_id
  30. path_key_expr = r"(current\s*\(\s*\)/" + rel_path_keyexpr + ")"
  31. path_equality_expr = node_id + r"\s*=\s*" + path_key_expr
  32. path_predicate = r"\s*\[\s*" + path_equality_expr + r"\s*\]\s*"
  33. absolute_path_arg = "(?:/" + node_id + "(" + path_predicate + ")*)+"
  34. descendant_path_arg = node_id + "(" + path_predicate + ")*" + \
  35. "(?:" + absolute_path_arg + ")?"
  36. relative_path_arg = r"(\.\./)*" + descendant_path_arg
  37. deref_path_arg = r"deref\s*\(\s*(?:" + relative_path_arg + ")\s*\)/\.\./" + relative_path_arg
  38. path_arg = "(" + absolute_path_arg + "|" + relative_path_arg + "|" + \
  39. deref_path_arg + ")"
  40. absolute_schema_nodeid = "(/" + node_id + ")+"
  41. descendant_schema_nodeid = node_id + "(" + absolute_schema_nodeid + ")?"
  42. schema_nodeid = "("+absolute_schema_nodeid+"|"+descendant_schema_nodeid+")"
  43. unique_arg = descendant_schema_nodeid + "(\s+" + descendant_schema_nodeid + ")*"
  44. key_arg = node_id + "(\s+" + node_id + ")*"
  45. re_schema_node_id_part = re.compile('/' + keyword)
  46. # URI - RFC 3986, Appendix A
  47. scheme = "[A-Za-z][-+.A-Za-z0-9]*"
  48. unreserved = "[-._~A-Za-z0-9]"
  49. pct_encoded = "%[0-9A-F]{2}"
  50. sub_delims = "[!$&'()*+,;=]"
  51. pchar = ("(" + unreserved + "|" + pct_encoded + "|" +
  52. sub_delims + "|[:@])")
  53. segment = pchar + "*"
  54. segment_nz = pchar + "+"
  55. userinfo = ("(" + unreserved + "|" + pct_encoded + "|" +
  56. sub_delims + "|:)*")
  57. dec_octet = "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"
  58. ipv4address = "(" + dec_octet + r"\.){3}" + dec_octet
  59. h16 = "[0-9A-F]{1,4}"
  60. ls32 = "(" + h16 + ":" + h16 + "|" + ipv4address + ")"
  61. ipv6address = (
  62. "((" + h16 + ":){6}" + ls32 +
  63. "|::(" + h16 + ":){5}" + ls32 +
  64. "|(" + h16 + ")?::(" + h16 + ":){4}" + ls32 +
  65. "|((" + h16 + ":)?" + h16 + ")?::(" + h16 + ":){3}" + ls32 +
  66. "|((" + h16 + ":){,2}" + h16 + ")?::(" + h16 + ":){2}" + ls32 +
  67. "|((" + h16 + ":){,3}" + h16 + ")?::" + h16 + ":" + ls32 +
  68. "|((" + h16 + ":){,4}" + h16 + ")?::" + ls32 +
  69. "|((" + h16 + ":){,5}" + h16 + ")?::" + h16 +
  70. "|((" + h16 + ":){,6}" + h16 + ")?::)")
  71. ipvfuture = r"v[0-9A-F]+\.(" + unreserved + "|" + sub_delims + "|:)+"
  72. ip_literal = r"\[(" + ipv6address + "|" + ipvfuture + r")\]"
  73. reg_name = "(" + unreserved + "|" + pct_encoded + "|" + sub_delims + ")*"
  74. host = "(" + ip_literal + "|" + ipv4address + "|" + reg_name + ")"
  75. port = "[0-9]*"
  76. authority = "(" + userinfo + "@)?" + host + "(:" + port + ")?"
  77. path_abempty = "(/" + segment + ")*"
  78. path_absolute = "/(" + segment_nz + "(/" + segment + ")*)?"
  79. path_rootless = segment_nz + "(/" + segment + ")*"
  80. path_empty = pchar + "{0}"
  81. hier_part = ("(" + "//" + authority + path_abempty + "|" +
  82. path_absolute + "|" + path_rootless + "|" + path_empty + ")")
  83. query = "(" + pchar + "|[/?])*"
  84. fragment = query
  85. uri = (scheme + ":" + hier_part + r"(\?" + query + ")?" +
  86. "(#" + fragment + ")?")
  87. # Date
  88. date = r"[1-2][0-9]{3}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"
  89. re_nonneg_integer = re.compile("^" + nonneg_integer + "$")
  90. re_integer = re.compile("^" + integer_ + "$")
  91. re_decimal = re.compile("^" + decimal_ + "$")
  92. re_uri = re.compile("^" + uri + "$")
  93. re_boolean = re.compile("^(true|false)$")
  94. re_version = re.compile("^1$")
  95. re_date = re.compile("^" + date +"$")
  96. re_status = re.compile("^(current|obsolete|deprecated)$")
  97. re_key = re.compile("^" + key_arg + "$")
  98. re_length = re.compile("^" + length_expr + "$")
  99. re_range = re.compile("^" + range_expr + "$")
  100. re_pos_integer = re.compile(r"^(unbounded|" + pos_integer + r")$")
  101. re_ordered_by = re.compile(r"^(user|system)$")
  102. re_node_id = re.compile("^" + node_id + "$")
  103. re_path = re.compile("^" + path_arg + "$")
  104. re_absolute_path = re.compile("^" + absolute_path_arg + "$")
  105. re_unique = re.compile("^" + unique_arg + "$")
  106. re_schema_nodeid = re.compile("^" + schema_nodeid + "$")
  107. re_absolute_schema_nodeid = re.compile("^" + absolute_schema_nodeid + "$")
  108. re_descendant_schema_nodeid = re.compile("^" + descendant_schema_nodeid + "$")
  109. re_deviate = re.compile("^(add|delete|replace|not-supported)$")
  110. arg_type_map = {
  111. "identifier": lambda s: re_identifier.search(s) is not None,
  112. "non-negative-integer": lambda s: re_nonneg_integer.search(s) is not None,
  113. "integer": lambda s: re_integer.search(s) is not None,
  114. "uri": lambda s: re_uri.search(s) is not None,
  115. "boolean": lambda s: re_boolean.search(s) is not None,
  116. "version": lambda s: re_version.search(s) is not None,
  117. "date": lambda s: re_date.search(s) is not None,
  118. "status-arg": lambda s: re_status.search(s) is not None,
  119. "key-arg": lambda s: re_key.search(s) is not None,
  120. "length-arg": lambda s: re_length.search(s) is not None,
  121. "range-arg": lambda s: re_range.search(s) is not None,
  122. "max-value": lambda s: re_pos_integer.search(s) is not None,
  123. "ordered-by-arg": lambda s: re_ordered_by.search(s) is not None,
  124. "identifier-ref": lambda s: re_node_id.search(s) is not None,
  125. "path-arg": lambda s: re_path.search(s) is not None,
  126. "absolute-path-arg": lambda s: re_absolute_path.search(s) is not None,
  127. "unique-arg": lambda s: re_unique.search(s) is not None,
  128. "absolute-schema-nodeid": lambda s: \
  129. re_absolute_schema_nodeid.search(s) is not None,
  130. "descendant-schema-nodeid": lambda s: \
  131. re_descendant_schema_nodeid.search(s) is not None,
  132. "schema-nodeid": lambda s: \
  133. re_schema_nodeid.search(s) is not None,
  134. "enum-arg": lambda s: chk_enum_arg(s),
  135. "fraction-digits-arg": lambda s: chk_fraction_digits_arg(s),
  136. "deviate-arg": lambda s: re_deviate.search(s) is not None,
  137. }
  138. """Argument type definitions.
  139. Regular expressions for all argument types except plain string that
  140. are checked directly by the parser.
  141. """
  142. def chk_enum_arg(s):
  143. """Checks if the string `s` is a valid enum string.
  144. Return True or False."""
  145. if len(s) == 0 or s[0].isspace() or s[-1].isspace():
  146. return False
  147. else:
  148. return True
  149. def chk_fraction_digits_arg(s):
  150. """Checks if the string `s` is a valid fraction-digits argument.
  151. Return True or False."""
  152. try:
  153. v = int(s)
  154. if v >= 1 and v <= 18:
  155. return True
  156. else:
  157. return False
  158. except ValueError:
  159. return False
  160. def add_arg_type(arg_type, regexp):
  161. """Add a new arg_type to the map.
  162. Used by extension plugins to register their own argument types."""
  163. arg_type_map[arg_type] = regexp
  164. # keyword argument-name yin-element
  165. yin_map = \
  166. {'anyxml': ('name', False),
  167. 'argument': ('name', False),
  168. 'augment': ('target-node', False),
  169. 'base': ('name', False),
  170. 'belongs-to': ('module', False),
  171. 'bit': ('name', False),
  172. 'case': ('name', False),
  173. 'choice': ('name', False),
  174. 'config': ('value', False),
  175. 'contact': ('text', True),
  176. 'container': ('name', False),
  177. 'default': ('value', False),
  178. 'description': ('text', True),
  179. 'deviate': ('value', False),
  180. 'deviation': ('target-node', False),
  181. 'enum': ('name', False),
  182. 'error-app-tag': ('value', False),
  183. 'error-message': ('value', True),
  184. 'extension': ('name', False),
  185. 'feature': ('name', False),
  186. 'fraction-digits': ('value', False),
  187. 'grouping': ('name', False),
  188. 'identity': ('name', False),
  189. 'if-feature': ('name', False),
  190. 'import': ('module', False),
  191. 'include': ('module', False),
  192. 'input': (None, None),
  193. 'key': ('value', False),
  194. 'leaf': ('name', False),
  195. 'leaf-list': ('name', False),
  196. 'length': ('value', False),
  197. 'list': ('name', False),
  198. 'mandatory': ('value', False),
  199. 'max-elements': ('value', False),
  200. 'min-elements': ('value', False),
  201. 'module': ('name', False),
  202. 'must': ('condition', False),
  203. 'namespace': ('uri', False),
  204. 'notification': ('name', False),
  205. 'ordered-by': ('value', False),
  206. 'organization': ('text', True),
  207. 'output': (None, None),
  208. 'path': ('value', False),
  209. 'pattern': ('value', False),
  210. 'position': ('value', False),
  211. 'presence': ('value', False),
  212. 'prefix': ('value', False),
  213. 'range': ('value', False),
  214. 'reference': ('text', True),
  215. 'refine': ('target-node', False),
  216. 'require-instance': ('value', False),
  217. 'revision': ('date', False),
  218. 'revision-date': ('date', False),
  219. 'rpc': ('name', False),
  220. 'status': ('value', False),
  221. 'submodule': ('name', False),
  222. 'type': ('name', False),
  223. 'typedef': ('name', False),
  224. 'unique': ('tag', False),
  225. 'units': ('name', False),
  226. 'uses': ('name', False),
  227. 'value': ('value', False),
  228. 'when': ('condition', False),
  229. 'yang-version': ('value', False),
  230. 'yin-element': ('value', False),
  231. }
  232. """Mapping of statements to the YIN representation of their arguments.
  233. The values are pairs whose first component specifies whether the
  234. argument is stored in a subelement and the second component is the
  235. name of the attribute or subelement carrying the argument. See YANG
  236. specification.
  237. """