From 77bfb0fb7bd4a86105e5b3c95c67d18c046a1651 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 7 Mar 2014 14:40:57 +0100 Subject: [PATCH] basic precedence algorithm - not tested yet --- jedi/evaluate/precedence.py | 150 +++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 70 deletions(-) diff --git a/jedi/evaluate/precedence.py b/jedi/evaluate/precedence.py index 3a174ede..26683749 100644 --- a/jedi/evaluate/precedence.py +++ b/jedi/evaluate/precedence.py @@ -12,37 +12,41 @@ class PythonGrammar(object): Some kind of mirror of http://docs.python.org/3/reference/grammar.html. """ - class AtStart(tuple): - pass - class MultiPart(str): def __new__(cls, first, second): self = str.__new__(cls, first) self.second = second - factor = AtStart(('+', '-', '~')) - power = '**', - term = '*', '/', '%', '//' - arith_expr = '+', '-' + def __str__(self): + return self.__str__() + ' ' + self.second - shift_expr = '<<', '>>' - and_expr = '&', - xor_expr = '^', - expr = '|', + FACTOR = '+', '-', '~' + POWER = '**', + TERM = '*', '/', '%', '//' + ARITH_EXPR = '+', '-' - comparison = ('<', '>', '==', '>=', '<=', '!=', 'in', - MultiPart('not', 'in'), 'is', MultiPart('is', 'not')) + SHIFT_EXPR = '<<', '>>' + AND_EXPR = '&', + XOR_EXPR = '^', + EXPR = '|', - not_test = AtStart(('not',)) - and_test = 'and', - or_test = 'or', + COMPARISON = ('<', '>', '==', '>=', '<=', '!=', 'in', + MultiPart('not', 'in'), MultiPart('is', 'not')), 'is' - #test = or_test ['if' or_test 'else' test] | lambdef + NOT_TEST = 'not', + AND_TEST = 'and', + OR_TEST = 'or', - #sliceop = ':' [test] - #subscript = test | [test] ':' [test] [sliceop] - order = (factor, power, term, arith_expr, shift_expr, and_expr, xor_expr, - expr, comparison, not_test, and_test, or_test) + #TEST = or_test ['if' or_test 'else' test] | lambdef + + #SLICEOP = ':' [test] + #SUBSCRIPT = test | [test] ':' [test] [sliceop] + ORDER = (POWER, TERM, ARITH_EXPR, SHIFT_EXPR, AND_EXPR, XOR_EXPR, + EXPR, COMPARISON, AND_TEST, OR_TEST) + + FACTOR_PRIORITY = 0 # highest priority + LOWEST_PRIORITY = len(ORDER) + NOT_TEST_PRIORITY = LOWEST_PRIORITY - 2 # priority only lower for `and`/`or` class Precedence(object): @@ -51,58 +55,64 @@ class Precedence(object): self.operator = operator self.right = right + def __repr__(self): + return '(%s %s %s)' % (self.left, self.operator, self.right) + def create_precedence(expression_list): - def get_op(current, expression_list): - for element in expression_list: - return - if not isinstance(obj, str): - debug.warning('normal element in place of operator: %s', element) + iterator = PushBackIterator(expression_list) + return _check_operator(iterator) + + +def _syntax_error(element, msg='SyntaxError in precedence'): + debug.warning('%s: %s, %s' % (msg, element, element.start_pos)) + + +def _get_number(iterator, priority=PythonGrammar.LOWEST_PRIORITY): + el = next(iterator) + if isinstance(el, pr.Operator): + if el in PythonGrammar.FACTOR: + right = _get_number(iterator, PythonGrammar.FACTOR_PRIORITY) + elif el in PythonGrammar.NOT_TEST and priority <= PythonGrammar.FACTOR_PRIORITY: + right = _get_number(iterator, PythonGrammar.NOT_TEST_PRIORITY) + else: + _syntax_error(el) + return _get_number(iterator, priority) + return Precedence(None, el, right) + else: + return el + + +def _check_operator(iterator, priority=PythonGrammar.LOWEST_PRIORITY): + """ + """ + left = _get_number(iterator, priority) + for el in iterator: + if not isinstance(el, pr.Operator): + _syntax_error(el) + continue + + operator = None + for check_prio, check in enumerate(PythonGrammar.ORDER): + if check_prio >= priority: + break # respect priorities. + + try: + match = check.index(el) + except ValueError: continue - def is_operator(obj): - if isinstance(obj, pr.Call): - element = str(obj.name) - for term in PythonGrammar.order: - pass - return element + if isinstance(match, PythonGrammar.MultiPart): + next_tok = next(iterator) + if next_tok != match.second: + iterator.push_back(next_tok) + continue - def tokenize(): - pass + operator = check + break - new - current = None - exp_iterator = PushBackIterator(expression_list) - for element in expression_list: - op_name = element - if isinstance(element, pr.Call): - op_name = str(element.name) - current = s - if isinstance(element, pr.Call): - x = str(element.name) - new = _process_element(element, expression_list) - if current is None: - current = new - else: - current = _process_element(element, expression_list) - return current - - -def _process_element(element, expression_list, previous=None): - if element is None: - return previous - - if isinstance(element, pr.Call): - element = str(element.name) - elif not isinstance(element, str): - if previous is None: - previous = element - return _process_element(expression_list, previous=previous) - - for term in PythonGrammar.order: - if element in term: - right = _process_element(expression_list) - if right is None: - return previous - else: - return Precedence(previous, element, right) + if operator is None: + _syntax_error(el) + continue + left = Precedence(left, operator, _check_operator(iterator, check_prio)) + return left