m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.7 KiB

6 months ago
  1. import logging
  2. import sys
  3. import os.path
  4. import ply.yacc
  5. from jsonpath_ng.exceptions import JsonPathParserError
  6. from jsonpath_ng.jsonpath import *
  7. from jsonpath_ng.lexer import JsonPathLexer
  8. logger = logging.getLogger(__name__)
  9. def parse(string):
  10. return JsonPathParser().parse(string)
  11. class JsonPathParser:
  12. '''
  13. An LALR-parser for JsonPath
  14. '''
  15. tokens = JsonPathLexer.tokens
  16. def __init__(self, debug=False, lexer_class=None):
  17. if self.__doc__ is None:
  18. raise JsonPathParserError(
  19. 'Docstrings have been removed! By design of PLY, '
  20. 'jsonpath-rw requires docstrings. You must not use '
  21. 'PYTHONOPTIMIZE=2 or python -OO.'
  22. )
  23. self.debug = debug
  24. self.lexer_class = lexer_class or JsonPathLexer # Crufty but works around statefulness in PLY
  25. def parse(self, string, lexer = None):
  26. lexer = lexer or self.lexer_class()
  27. return self.parse_token_stream(lexer.tokenize(string))
  28. def parse_token_stream(self, token_iterator, start_symbol='jsonpath'):
  29. # Since PLY has some crufty aspects and dumps files, we try to keep them local
  30. # However, we need to derive the name of the output Python file :-/
  31. output_directory = os.path.dirname(__file__)
  32. try:
  33. module_name = os.path.splitext(os.path.split(__file__)[1])[0]
  34. except:
  35. module_name = __name__
  36. parsing_table_module = '_'.join([module_name, start_symbol, 'parsetab'])
  37. # And we regenerate the parse table every time;
  38. # it doesn't actually take that long!
  39. new_parser = ply.yacc.yacc(module=self,
  40. debug=self.debug,
  41. tabmodule = parsing_table_module,
  42. outputdir = output_directory,
  43. write_tables=0,
  44. start = start_symbol,
  45. errorlog = logger)
  46. return new_parser.parse(lexer = IteratorToTokenStream(token_iterator))
  47. # ===================== PLY Parser specification =====================
  48. precedence = [
  49. ('left', ','),
  50. ('left', 'DOUBLEDOT'),
  51. ('left', '.'),
  52. ('left', '|'),
  53. ('left', '&'),
  54. ('left', 'WHERE'),
  55. ]
  56. def p_error(self, t):
  57. if t is None:
  58. raise JsonPathParserError('Parse error near the end of string!')
  59. raise JsonPathParserError('Parse error at %s:%s near token %s (%s)'
  60. % (t.lineno, t.col, t.value, t.type))
  61. def p_jsonpath_binop(self, p):
  62. """jsonpath : jsonpath '.' jsonpath
  63. | jsonpath DOUBLEDOT jsonpath
  64. | jsonpath WHERE jsonpath
  65. | jsonpath '|' jsonpath
  66. | jsonpath '&' jsonpath"""
  67. op = p[2]
  68. if op == '.':
  69. p[0] = Child(p[1], p[3])
  70. elif op == '..':
  71. p[0] = Descendants(p[1], p[3])
  72. elif op == 'where':
  73. p[0] = Where(p[1], p[3])
  74. elif op == '|':
  75. p[0] = Union(p[1], p[3])
  76. elif op == '&':
  77. p[0] = Intersect(p[1], p[3])
  78. def p_jsonpath_fields(self, p):
  79. "jsonpath : fields_or_any"
  80. p[0] = Fields(*p[1])
  81. def p_jsonpath_named_operator(self, p):
  82. "jsonpath : NAMED_OPERATOR"
  83. if p[1] == 'this':
  84. p[0] = This()
  85. elif p[1] == 'parent':
  86. p[0] = Parent()
  87. else:
  88. raise JsonPathParserError('Unknown named operator `%s` at %s:%s'
  89. % (p[1], p.lineno(1), p.lexpos(1)))
  90. def p_jsonpath_root(self, p):
  91. "jsonpath : '$'"
  92. p[0] = Root()
  93. def p_jsonpath_idx(self, p):
  94. "jsonpath : '[' idx ']'"
  95. p[0] = p[2]
  96. def p_jsonpath_slice(self, p):
  97. "jsonpath : '[' slice ']'"
  98. p[0] = p[2]
  99. def p_jsonpath_fieldbrackets(self, p):
  100. "jsonpath : '[' fields ']'"
  101. p[0] = Fields(*p[2])
  102. def p_jsonpath_child_fieldbrackets(self, p):
  103. "jsonpath : jsonpath '[' fields ']'"
  104. p[0] = Child(p[1], Fields(*p[3]))
  105. def p_jsonpath_child_idxbrackets(self, p):
  106. "jsonpath : jsonpath '[' idx ']'"
  107. p[0] = Child(p[1], p[3])
  108. def p_jsonpath_child_slicebrackets(self, p):
  109. "jsonpath : jsonpath '[' slice ']'"
  110. p[0] = Child(p[1], p[3])
  111. def p_jsonpath_parens(self, p):
  112. "jsonpath : '(' jsonpath ')'"
  113. p[0] = p[2]
  114. # Because fields in brackets cannot be '*' - that is reserved for array indices
  115. def p_fields_or_any(self, p):
  116. """fields_or_any : fields
  117. | '*' """
  118. if p[1] == '*':
  119. p[0] = ['*']
  120. else:
  121. p[0] = p[1]
  122. def p_fields_id(self, p):
  123. "fields : ID"
  124. p[0] = [p[1]]
  125. def p_fields_comma(self, p):
  126. "fields : fields ',' fields"
  127. p[0] = p[1] + p[3]
  128. def p_idx(self, p):
  129. "idx : NUMBER"
  130. p[0] = Index(p[1])
  131. def p_slice_any(self, p):
  132. "slice : '*'"
  133. p[0] = Slice()
  134. def p_slice(self, p): # Currently does not support `step`
  135. """slice : maybe_int ':' maybe_int
  136. | maybe_int ':' maybe_int ':' maybe_int """
  137. p[0] = Slice(*p[1::2])
  138. def p_maybe_int(self, p):
  139. """maybe_int : NUMBER
  140. | empty"""
  141. p[0] = p[1]
  142. def p_empty(self, p):
  143. 'empty :'
  144. p[0] = None
  145. class IteratorToTokenStream:
  146. def __init__(self, iterator):
  147. self.iterator = iterator
  148. def token(self):
  149. try:
  150. return next(self.iterator)
  151. except StopIteration:
  152. return None
  153. if __name__ == '__main__':
  154. logging.basicConfig()
  155. parser = JsonPathParser(debug=True)
  156. print(parser.parse(sys.stdin.read()))