<commit_before>"""
Simplification: all subtraction operations are converted to addition of
a negated term (e.g., `1-2*2+3` becomes `1+(-1)*(2*2)+3`). Therefore, we
have no subtraction operations in our binary expression tree. Similarly,
all division operations are converted to multiplication of the reciprocal
of the factor (e.g., `1/2*3` becomes `1*(1/2)*3`). Therefore, we have no
division nodes in our binary expression tree.

See futher discussion of binary expression trees in the docstring for
`parse_expression`.
"""


from __future__ import division
from operator import add, mul
from timeit import timeit


DIGITS = '1234567890'


def eval_arithmetic_expression(arithmetic_expression_string):
    arithmetic_node, i = parse_expression(arithmetic_expression_string)
    assert i == len(arithmetic_expression_string)  # Whole string has been parsed.
    return arithmetic_node.calculate()


def parse_expression(s, i=0, negative_first_term=False):
    """Returns a binary expression tree created from the arithmetic expression
    encoded in the string s. The leaf nodes of the tree are integers, and all
    other nodes are arithmetic operations.

    See: https://en.wikipedia.org/wiki/Binary_expression_tree
    """
    left_node, i = parse_term(s, i)

    if negative_first_term:
        left_node = negate(left_node)

    assert i == len(s) or s[i] in '+-', 'Invalid arithmetic expression'

    if i == len(s):
        return left_node, i
    elif s[i] in '+-':
        right_node, i = parse_expression(s, i+1, s[i] == '-')
        return AdditionNode(left_node, right_node), i


def parse_term(s, i, take_reciprocal_of_first_factor=False):
    left_node, i = parse_factor(s, i)

    if take_reciprocal_of_first_factor:
        left_node = ReciprocalNode(left_node)

    assert i == len(s) or s[i] in '+-*/', 'Invalid arithmetic expression'

    if i == len(s) or s[i] in '+-':
        return left_node, i
    elif s[i] in '*/':
        right_node, i = parse_term(s, i+1, s[i] == '/')
        return MultiplicationNode(left_node, right_node), i


def parse_factor(s, i):
    # All possible fators: positive and negated integers, and
    # positive and negated parenthetic expressions.

    assert s[i] in DIGITS+'-('

    if s[i] == '-':
        assert s[i+1] in DIGITS+'('
        node, i = parse_factor(s, i+1)
        return negate(node), i
    elif s[i] in DIGITS:
        return parse_integer(s, i)
    else:  # s[i] == '('
        pass


def parse_integer(s, i):
    j = i

    while j < len(s) and s[j] in DIGITS:
        j += 1

    return NumberNode(int(s[i:j])), j


def negate(node):
    return MultiplicationNode(NumberNode(-1), node)


class OperationNode:
    def __init__(self, left_node, right_node):
        self.left_node = left_node
        self.right_node = right_node

    def calculate(self):
        return self.operation(self.left_node.calculate(), self.right_node.calculate())


class AdditionNode(OperationNode):
    operation = add


class MultiplicationNode(OperationNode):
    operation = mul


class ReciprocalNode:
    def __init__(self, denominator_node):
        self.denominator_node = denominator_node

    def calculate(self):
        return 1 / self.denominator_node.calculate()<commit_msg>Shorten up `parse_integer` in arithmetic_eval/iteration3.py.<commit_after>"""
Simplification: all subtraction operations are converted to addition of
a negated term (e.g., `1-2*2+3` becomes `1+(-1)*(2*2)+3`). Therefore, we
have no subtraction operations in our binary expression tree. Similarly,
all division operations are converted to multiplication of the reciprocal
of the factor (e.g., `1/2*3` becomes `1*(1/2)*3`). Therefore, we have no
division nodes in our binary expression tree.

See futher discussion of binary expression trees in the docstring for
`parse_expression`.
"""


from __future__ import division
from operator import add, mul
from timeit import timeit


DIGITS = '1234567890'


def eval_arithmetic_expression(arithmetic_expression_string):
    arithmetic_node, i = parse_expression(arithmetic_expression_string)
    assert i == len(arithmetic_expression_string)  # Whole string has been parsed.
    return arithmetic_node.calculate()


def parse_expression(s, i=0, negative_first_term=False):
    """Returns a binary expression tree created from the arithmetic expression
    encoded in the string s. The leaf nodes of the tree are integers, and all
    other nodes are arithmetic operations.

    See: https://en.wikipedia.org/wiki/Binary_expression_tree
    """
    left_node, i = parse_term(s, i)

    if negative_first_term:
        left_node = negate(left_node)

    assert i == len(s) or s[i] in '+-', 'Invalid arithmetic expression'

    if i == len(s):
        return left_node, i
    elif s[i] in '+-':
        right_node, i = parse_expression(s, i+1, s[i] == '-')
        return AdditionNode(left_node, right_node), i


def parse_term(s, i, take_reciprocal_of_first_factor=False):
    left_node, i = parse_factor(s, i)

    if take_reciprocal_of_first_factor:
        left_node = ReciprocalNode(left_node)

    assert i == len(s) or s[i] in '+-*/', 'Invalid arithmetic expression'

    if i == len(s) or s[i] in '+-':
        return left_node, i
    elif s[i] in '*/':
        right_node, i = parse_term(s, i+1, s[i] == '/')
        return MultiplicationNode(left_node, right_node), i


def parse_factor(s, i):
    # All possible fators: positive and negated integers, and
    # positive and negated parenthetic expressions.

    assert s[i] in DIGITS+'-('

    if s[i] == '-':
        assert s[i+1] in DIGITS+'('
        node, i = parse_factor(s, i+1)
        return negate(node), i
    elif s[i] in DIGITS:
        return parse_integer(s, i)
    else:  # s[i] == '('
        pass


def parse_integer(s, i):
    j = next((j for j in xrange(i+1, len(s)) if s[j] not in DIGITS), len(s))
    return NumberNode(int(s[i:j])), j


def negate(node):
    return MultiplicationNode(NumberNode(-1), node)


class OperationNode:
    def __init__(self, left_node, right_node):
        self.left_node = left_node
        self.right_node = right_node

    def calculate(self):
        return self.operation(self.left_node.calculate(), self.right_node.calculate())


class AdditionNode(OperationNode):
    operation = add


class MultiplicationNode(OperationNode):
    operation = mul


class ReciprocalNode:
    def __init__(self, denominator_node):
        self.denominator_node = denominator_node

    def calculate(self):
        return 1 / self.denominator_node.calculate()
{'fraction_non_alphanumeric': 0.11015911872705018, 'fraction_numerical': 0.010556915544675643, 'mean_word_length': 3.514502762430939, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3840391', 'n_tokens_mistral': 2178, 'n_tokens_neox': 2044, 'n_words': 629}