Source code for pyMSpec.pyisocalc.canopy.sum_formula

from collections import defaultdict
import re


[docs]class TreeNode(object): def __init__(self, text, offset, elements=None): self.text = text self.offset = offset self.elements = elements or [] def __iter__(self): for el in self.elements: yield el
[docs]class TreeNode1(TreeNode): def __init__(self, text, offset, elements): super(TreeNode1, self).__init__(text, offset, elements) self.complex = elements[0]
[docs]class TreeNode2(TreeNode): def __init__(self, text, offset, elements): super(TreeNode2, self).__init__(text, offset, elements) self.complex = elements[1]
[docs]class TreeNode3(TreeNode): def __init__(self, text, offset, elements): super(TreeNode3, self).__init__(text, offset, elements) self.fragment = elements[1]
[docs]class TreeNode4(TreeNode): def __init__(self, text, offset, elements): super(TreeNode4, self).__init__(text, offset, elements) self.element = elements[0] self.num = elements[1]
[docs]class TreeNode5(TreeNode): def __init__(self, text, offset, elements): super(TreeNode5, self).__init__(text, offset, elements) self.sign = elements[0] self.complex = elements[1]
[docs]class ParseError(SyntaxError): pass
FAILURE = object()
[docs]class Grammar(object): REGEX_1 = re.compile('^[+ -]') REGEX_2 = re.compile('^[A-Z]') REGEX_3 = re.compile('^[a-z]') REGEX_4 = re.compile('^[0-9]') def _read_formula(self): address0, index0 = FAILURE, self._offset cached = self._cache['formula'].get(index0) if cached: self._offset = cached[1] return cached[0] index1, elements0 = self._offset, [] address1 = FAILURE address1 = self._read_complex() if address1 is not FAILURE: elements0.append(address1) address2 = FAILURE remaining0, index2, elements1, address3 = 0, self._offset, [], True while address3 is not FAILURE: index3, elements2 = self._offset, [] address4 = FAILURE chunk0 = None if self._offset < self._input_size: chunk0 = self._input[self._offset:self._offset + 1] if chunk0 == '.': address4 = TreeNode(self._input[self._offset:self._offset + 1], self._offset) self._offset = self._offset + 1 else: address4 = FAILURE if self._offset > self._failure: self._failure = self._offset self._expected = [] if self._offset == self._failure: self._expected.append('"."') if address4 is not FAILURE: elements2.append(address4) address5 = FAILURE address5 = self._read_complex() if address5 is not FAILURE: elements2.append(address5) else: elements2 = None self._offset = index3 else: elements2 = None self._offset = index3 if elements2 is None: address3 = FAILURE else: address3 = TreeNode2(self._input[index3:self._offset], index3, elements2) self._offset = self._offset if address3 is not FAILURE: elements1.append(address3) remaining0 -= 1 if remaining0 <= 0: address2 = TreeNode(self._input[index2:self._offset], index2, elements1) self._offset = self._offset else: address2 = FAILURE if address2 is not FAILURE: elements0.append(address2) address6 = FAILURE remaining1, index4, elements3, address7 = 0, self._offset, [], True while address7 is not FAILURE: address7 = self._read_adduct() if address7 is not FAILURE: elements3.append(address7) remaining1 -= 1 if remaining1 <= 0: address6 = TreeNode(self._input[index4:self._offset], index4, elements3) self._offset = self._offset else: address6 = FAILURE if address6 is not FAILURE: elements0.append(address6) else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 if elements0 is None: address0 = FAILURE else: address0 = self._actions.make_formula(self._input, index1, self._offset, elements0) self._offset = self._offset self._cache['formula'][index0] = (address0, self._offset) return address0 def _read_complex(self): address0, index0 = FAILURE, self._offset cached = self._cache['complex'].get(index0) if cached: self._offset = cached[1] return cached[0] index1, elements0 = self._offset, [] address1 = FAILURE index2 = self._offset address1 = self._read_number() if address1 is FAILURE: address1 = TreeNode(self._input[index2:index2], index2) self._offset = index2 if address1 is not FAILURE: elements0.append(address1) address2 = FAILURE remaining0, index3, elements1, address3 = 1, self._offset, [], True while address3 is not FAILURE: address3 = self._read_fragment() if address3 is not FAILURE: elements1.append(address3) remaining0 -= 1 if remaining0 <= 0: address2 = TreeNode(self._input[index3:self._offset], index3, elements1) self._offset = self._offset else: address2 = FAILURE if address2 is not FAILURE: elements0.append(address2) else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 if elements0 is None: address0 = FAILURE else: address0 = self._actions.expand_complex(self._input, index1, self._offset, elements0) self._offset = self._offset self._cache['complex'][index0] = (address0, self._offset) return address0 def _read_fragment(self): address0, index0 = FAILURE, self._offset cached = self._cache['fragment'].get(index0) if cached: self._offset = cached[1] return cached[0] index1 = self._offset address0 = self._read_non_expanded_fragment() if address0 is FAILURE: self._offset = index1 address0 = self._read_expanded_fragment() if address0 is FAILURE: self._offset = index1 self._cache['fragment'][index0] = (address0, self._offset) return address0 def _read_non_expanded_fragment(self): address0, index0 = FAILURE, self._offset cached = self._cache['non_expanded_fragment'].get(index0) if cached: self._offset = cached[1] return cached[0] index1, elements0 = self._offset, [] address1 = FAILURE chunk0 = None if self._offset < self._input_size: chunk0 = self._input[self._offset:self._offset + 1] if chunk0 == '(': address1 = TreeNode(self._input[self._offset:self._offset + 1], self._offset) self._offset = self._offset + 1 else: address1 = FAILURE if self._offset > self._failure: self._failure = self._offset self._expected = [] if self._offset == self._failure: self._expected.append('"("') if address1 is not FAILURE: elements0.append(address1) address2 = FAILURE address2 = self._read_fragment() if address2 is not FAILURE: elements0.append(address2) address3 = FAILURE chunk1 = None if self._offset < self._input_size: chunk1 = self._input[self._offset:self._offset + 1] if chunk1 == ')': address3 = TreeNode(self._input[self._offset:self._offset + 1], self._offset) self._offset = self._offset + 1 else: address3 = FAILURE if self._offset > self._failure: self._failure = self._offset self._expected = [] if self._offset == self._failure: self._expected.append('")"') if address3 is not FAILURE: elements0.append(address3) address4 = FAILURE index2 = self._offset address4 = self._read_number() if address4 is FAILURE: address4 = TreeNode(self._input[index2:index2], index2) self._offset = index2 if address4 is not FAILURE: elements0.append(address4) else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 if elements0 is None: address0 = FAILURE else: address0 = self._actions.expand_fragment(self._input, index1, self._offset, elements0) self._offset = self._offset self._cache['non_expanded_fragment'][index0] = (address0, self._offset) return address0 def _read_expanded_fragment(self): address0, index0 = FAILURE, self._offset cached = self._cache['expanded_fragment'].get(index0) if cached: self._offset = cached[1] return cached[0] remaining0, index1, elements0, address1 = 1, self._offset, [], True while address1 is not FAILURE: address1 = self._read_simple_fragment() if address1 is not FAILURE: elements0.append(address1) remaining0 -= 1 if remaining0 <= 0: address0 = self._actions.combine_fragments(self._input, index1, self._offset, elements0) self._offset = self._offset else: address0 = FAILURE self._cache['expanded_fragment'][index0] = (address0, self._offset) return address0 def _read_simple_fragment(self): address0, index0 = FAILURE, self._offset cached = self._cache['simple_fragment'].get(index0) if cached: self._offset = cached[1] return cached[0] index1, elements0 = self._offset, [] address1 = FAILURE address1 = self._read_element() if address1 is not FAILURE: elements0.append(address1) address2 = FAILURE index2 = self._offset address2 = self._read_number() if address2 is FAILURE: address2 = TreeNode(self._input[index2:index2], index2) self._offset = index2 if address2 is not FAILURE: elements0.append(address2) else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 if elements0 is None: address0 = FAILURE else: address0 = self._actions.make_simple_fragment(self._input, index1, self._offset, elements0) self._offset = self._offset self._cache['simple_fragment'][index0] = (address0, self._offset) return address0 def _read_adduct(self): address0, index0 = FAILURE, self._offset cached = self._cache['adduct'].get(index0) if cached: self._offset = cached[1] return cached[0] index1, elements0 = self._offset, [] address1 = FAILURE address1 = self._read_sign() if address1 is not FAILURE: elements0.append(address1) address2 = FAILURE address2 = self._read_complex() if address2 is not FAILURE: elements0.append(address2) else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 if elements0 is None: address0 = FAILURE else: address0 = self._actions.multiply_by_sign(self._input, index1, self._offset, elements0) self._offset = self._offset self._cache['adduct'][index0] = (address0, self._offset) return address0 def _read_sign(self): address0, index0 = FAILURE, self._offset cached = self._cache['sign'].get(index0) if cached: self._offset = cached[1] return cached[0] chunk0 = None if self._offset < self._input_size: chunk0 = self._input[self._offset:self._offset + 1] if chunk0 is not None and Grammar.REGEX_1.search(chunk0): address0 = TreeNode(self._input[self._offset:self._offset + 1], self._offset) self._offset = self._offset + 1 else: address0 = FAILURE if self._offset > self._failure: self._failure = self._offset self._expected = [] if self._offset == self._failure: self._expected.append('[+ -]') self._cache['sign'][index0] = (address0, self._offset) return address0 def _read_element(self): address0, index0 = FAILURE, self._offset cached = self._cache['element'].get(index0) if cached: self._offset = cached[1] return cached[0] index1, elements0 = self._offset, [] address1 = FAILURE chunk0 = None if self._offset < self._input_size: chunk0 = self._input[self._offset:self._offset + 1] if chunk0 is not None and Grammar.REGEX_2.search(chunk0): address1 = TreeNode(self._input[self._offset:self._offset + 1], self._offset) self._offset = self._offset + 1 else: address1 = FAILURE if self._offset > self._failure: self._failure = self._offset self._expected = [] if self._offset == self._failure: self._expected.append('[A-Z]') if address1 is not FAILURE: elements0.append(address1) address2 = FAILURE remaining0, index2, elements1, address3 = 0, self._offset, [], True while address3 is not FAILURE: chunk1 = None if self._offset < self._input_size: chunk1 = self._input[self._offset:self._offset + 1] if chunk1 is not None and Grammar.REGEX_3.search(chunk1): address3 = TreeNode(self._input[self._offset:self._offset + 1], self._offset) self._offset = self._offset + 1 else: address3 = FAILURE if self._offset > self._failure: self._failure = self._offset self._expected = [] if self._offset == self._failure: self._expected.append('[a-z]') if address3 is not FAILURE: elements1.append(address3) remaining0 -= 1 if remaining0 <= 0: address2 = TreeNode(self._input[index2:self._offset], index2, elements1) self._offset = self._offset else: address2 = FAILURE if address2 is not FAILURE: elements0.append(address2) else: elements0 = None self._offset = index1 else: elements0 = None self._offset = index1 if elements0 is None: address0 = FAILURE else: address0 = self._actions.make_element(self._input, index1, self._offset, elements0) self._offset = self._offset self._cache['element'][index0] = (address0, self._offset) return address0 def _read_number(self): address0, index0 = FAILURE, self._offset cached = self._cache['number'].get(index0) if cached: self._offset = cached[1] return cached[0] remaining0, index1, elements0, address1 = 1, self._offset, [], True while address1 is not FAILURE: chunk0 = None if self._offset < self._input_size: chunk0 = self._input[self._offset:self._offset + 1] if chunk0 is not None and Grammar.REGEX_4.search(chunk0): address1 = TreeNode(self._input[self._offset:self._offset + 1], self._offset) self._offset = self._offset + 1 else: address1 = FAILURE if self._offset > self._failure: self._failure = self._offset self._expected = [] if self._offset == self._failure: self._expected.append('[0-9]') if address1 is not FAILURE: elements0.append(address1) remaining0 -= 1 if remaining0 <= 0: address0 = self._actions.make_number(self._input, index1, self._offset, elements0) self._offset = self._offset else: address0 = FAILURE self._cache['number'][index0] = (address0, self._offset) return address0
[docs]class Parser(Grammar): def __init__(self, input, actions, types): self._input = input self._input_size = len(input) self._actions = actions self._types = types self._offset = 0 self._cache = defaultdict(dict) self._failure = 0 self._expected = []
[docs] def parse(self): tree = self._read_formula() if tree is not FAILURE and self._offset == self._input_size: return tree if not self._expected: self._failure = self._offset self._expected.append('<EOF>') raise ParseError(format_error(self._input, self._failure, self._expected))
[docs]def format_error(input, offset, expected): lines, line_no, position = input.split('\n'), 0, 0 while position <= offset: position += len(lines[line_no]) + 1 line_no += 1 message, line = 'Line ' + str(line_no) + ': expected ' + ', '.join(expected) + '\n', lines[line_no - 1] message += line + '\n' position -= len(line) + 1 message += ' ' * (offset - position) return message + '^'
[docs]def parse(input, actions=None, types=None): parser = Parser(input, actions, types) return parser.parse()