Skip to content

Instantly share code, notes, and snippets.

@berdario
Last active August 29, 2015 14:05
Show Gist options
  • Save berdario/c7ff95e090c4efa299ab to your computer and use it in GitHub Desktop.
Save berdario/c7ff95e090c4efa299ab to your computer and use it in GitHub Desktop.
#! /usr/bin/env python
from enum import Enum
from numbers import Number
from operator import add, sub, mul, truediv, mod
class Operation(Enum):
PLUS = (add, 6)
MINUS = (sub, 6)
MULT = (mul, 7)
QUOT = (truediv, 7)
MOD = (mod, 7)
def __init__(self, fn, precedence):
self.fn = fn
self.precedence = precedence
ops_table = {'+': 'PLUS', '-': 'MINUS', '*': 'MULT', '/': 'QUOT', '%': 'MOD'}
class AST:
def __init__(self, v1, op=None, v2=None):
if op is None and v2 is None:
self.root = v1
self.l = self.r = None
self.precedence = 10
else:
self.root = op
self.precedence = op.precedence
self.l = v1
self.r = v2
def append(self, op, v):
if op.precedence > self.precedence:
self.r = AST(self.r, op, AST(v))
return self
else:
return AST(self, op, AST(v))
def evaluate(self):
if isinstance(self.root, Number):
return self.root
elif isinstance(self.root, Operation):
return self.root.fn(self.l.evaluate(), self.r.evaluate())
else:
raise Exception("sorry, this shouldn't happen, root is: %s", self.root)
def __str__(self):
if isinstance(self.root, Number):
return str(self.root)
elif isinstance(self.root, Operation):
return '({} {} {})'.format(self.root, self.l, self.r)
def parse(s):
n, *rest = s.split()
ast = AST(int(n))
while rest:
op, v, *rest = rest
assert op in ops_table, "%s is not a valid operation" % op
ast = ast.append(Operation[ops_table[op]], int(v))
return ast
if __name__ == '__main__':
while True:
expr = parse(input('> '))
print(expr.evaluate())
import pytest
# run the tests with py.test calc.py
def test_single_value():
assert parse('0').evaluate() == 0
assert parse('5').evaluate() == 5
assert parse('100000000000000000000').evaluate() == 100000000000000000000
def test_5ops():
assert parse('1 + 1').evaluate() == 2
assert parse('1 - 1').evaluate() == 0
assert parse('1 * 3').evaluate() == 3
assert parse('12 / 3').evaluate() == 4
assert parse('14 % 5').evaluate() == 4
def test_combined_exprs():
assert parse('1 + 1 + 1').evaluate() == 3
assert parse('1 - 1 - 1').evaluate() == -1
assert parse('2 * 3 - 1').evaluate() == 5
assert parse('2 - 6 / 2').evaluate() == -1
assert parse('1 + 1 - 4 * 4').evaluate() == -14
py==1.4.23
pytest==2.6.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment