Advertisement
Guest User

Untitled

a guest
Feb 27th, 2020
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.55 KB | None | 0 0
  1. import collections
  2. import re
  3.  
  4. def compile(source):
  5. return Parser(source)
  6.  
  7. Token = collections.namedtuple('Token', ['type', 'value', 'line', 'column'])
  8. Expression = collections.namedtuple('Expression', ['type', 'sub', 'max', 'min'])
  9.  
  10. class Parser:
  11.  
  12. length = 1
  13. code = "True"
  14. cols = set()
  15. def __init__(self, source):
  16. tokenizer = Parser.tokenize(source)
  17. condition = Parser.get_exp(tokenizer)
  18. self.code, self.cols = Parser.get_string(condition)
  19. try:
  20. self.length = condition.max - condition.min + 1
  21. except TypeError:
  22. #either min or max or both are un-set, thus the minimum trace length is 1
  23. self.length = 1
  24.  
  25. def get_string(expression):
  26. #print(expression)
  27. list = []
  28. cols = set()
  29. #print(isinstance(expression, Token))
  30. if isinstance(expression, str):
  31. return expression, set()
  32. if isinstance(expression, Token):
  33. if expression.type == 'ATOM':
  34. return expression.value.capitalize(), set()
  35. elif expression.type == 'NUMBER':
  36. return str(expression.value), set()
  37. elif expression.type == 'FUNCTION':
  38. print(expression)
  39. return str(expression.value)
  40. else:
  41. for x in expression.sub:
  42. sub = Parser.get_string(x)
  43. list.append(sub[0])
  44. cols.update(sub[1])
  45. if expression.type == 'COMPERATOR':
  46. print(list[0])
  47. print(list[1])
  48. col = ' '.join(list)
  49. print()
  50. return "ยง(" + col + ')', {col}
  51. inner = ','.join(list)
  52. if expression.type == 'None':
  53. return inner, set()
  54. code = expression.type.format(inner) if '{}' in expression.type else expression.type + '(' + inner + ')'
  55. return code, cols
  56.  
  57. comperators = {
  58. '>': 'GREATER',
  59. '<': 'LESSER',
  60. '>=': 'GREATER_EQUAL',
  61. '<=': 'LESSER_EQUAL',
  62. '==': 'EQUAL',
  63. '!=': 'NOT_EQUAL',
  64. '<>': 'NOT_EQUAL',
  65. }
  66. def get_exp(tokenizer):
  67. c_sub = []
  68. c_type = 'None'
  69. #The endpoint of the expression
  70. c_max = 1
  71. #The startingpoint of the expression
  72. c_min = 1
  73.  
  74. for t in tokenizer:
  75. #Go one level deeper
  76. if t.type == 'OPEN':
  77. sub = Parser.get_exp(tokenizer)
  78. c_max = max(sub.max, c_max) if isinstance(sub, int) else ''
  79. c_min = min(sub.min, c_min) if isinstance(sub, int) else ''
  80. c_sub.append(sub)
  81. #return from a sub-expression
  82. elif t.type == 'CLOSE':
  83. return Expression(c_type, c_sub, c_max, c_min)
  84. elif t.type == 'COMPERATOR':
  85. c_type = 'COMPERATOR'
  86. c_sub.append(Parser.comperators[t.value])
  87. elif t.type in ['AND', 'mean']:
  88. c_type = t.type
  89. elif t.type == 'SLICER':
  90. #deconstruct the slicer
  91. values = [int(x) if isint(x) else '' for x in t.value[1:-1].split(':')]
  92. if len(values) == 1:
  93. #slicer is of form [int]
  94. c_min = c_max = values[0]
  95. else:
  96. #slicer is of form [int:int]
  97. c_min, c_max = values
  98.  
  99. try:
  100. always_value = ',' + str(c_max - c_min + 1)
  101. except TypeError:
  102. always_value = ''
  103.  
  104. #Restructure the slicer into a NEXT(ALWAYS()) Expression
  105. if c_min == 0 or c_min == '': c_type = 'ALWAYS({}' + always_value + ')'
  106. else: c_type = 'NEXT(ALWAYS({}' + always_value + '),' + str(c_min) + ')'
  107. else:
  108. c_sub.append(t)
  109.  
  110. return Expression(c_type, c_sub, c_max, c_min)
  111.  
  112. def tokenize(code):
  113. keywords = {'AND', 'OR', 'UNTIL'}
  114. token_specification = [
  115. ('NUMBER', r'\d+(\.\d*)?'),
  116. ('ACCESSOR', r'@\w+:\w+'),
  117. ('OPEN', r'\('),
  118. ('CLOSE', r'\)'),
  119. ('SLICER', r'\[\d*:?\d*\]'),
  120. ('ATOM', r'true|false'),
  121. ('KEYWORD', '|'.join(keywords)),
  122. ('FUNCTION', r'[A-Za-z_]+'),
  123. ('VARIABLE', r'\$[A-Za-z_]+\w*'),
  124. ('COMPERATOR', r'>=|<=|==|!=|<>|>|<'),
  125. ('NEWLINE', r'\n'),
  126. ('SKIP', r'\s'),
  127. ('MISMATCH', r'.'),
  128. ]
  129. tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
  130. line_num = 1
  131. line_start = 0
  132. for mo in re.finditer(tok_regex, code):
  133. kind = mo.lastgroup
  134. value = mo.group()
  135. column = mo.start() - line_start
  136. if kind == 'NUMBER':
  137. value = float(value) if '.' in value else int(value)
  138. elif kind == 'KEYWORD':
  139. kind = value
  140. elif kind == 'NEWLINE':
  141. line_start = mo.end()
  142. line_num += 1
  143. continue
  144. elif kind == 'SKIP':
  145. continue
  146. elif kind == 'MISMATCH':
  147. raise RuntimeError(f'{value!r} unexpected on line {line_num}')
  148. yield Token(kind, value, line_num, column)
  149.  
  150.  
  151. def __str__(self):
  152. return str(self.cols) + '\n[' + str(self.length) + ']\n' + self.code
  153.  
  154. def isint(s):
  155. try:
  156. int(s)
  157. return True
  158. except ValueError:
  159. return False
  160.  
  161. if __name__ == '__main__':
  162. #print(compile('(true)[:1]'))
  163. print(compile('($steps >= 50) AND (mean($my_var 100) > 20)'))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement