Skip to content

Commit

Permalink
Changed evaluate() to use Values instead of Tokens.
Browse files Browse the repository at this point in the history
  • Loading branch information
nrubin29 committed Sep 16, 2017
1 parent 0260027 commit 6c94d11
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 41 deletions.
24 changes: 10 additions & 14 deletions ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,25 @@ def _fixed(self, ast):
return ast

def evaluate(self, vrs: Dict[str, RuleMatch]):
res = self._evaluate(self.ast, vrs)
return self._evaluate(self.ast, vrs)

if isinstance(res, Token):
return Value(value_map[res.name], res.value)

return res

def _evaluate(self, ast, vrs: Dict[str, RuleMatch]) -> Union[Dict[str, RuleMatch], Token]:
def _evaluate(self, ast, vrs: Dict[str, RuleMatch]): # -> Union[Dict[str, RuleMatch], Token]:
if ast.name == 'idt':
return {ast.matched[0].value: ast.matched[1]}

for i in range(len(ast.matched)):
token = ast.matched[i]
for token in ast.matched:
if isinstance(token, RuleMatch) and not token.value:
token.value = self._evaluate(token, vrs)

if any(map(lambda t: isinstance(t, RuleMatch), ast.matched)):
return calc_map[ast.name](ast.matched)

if isinstance(token, RuleMatch):
ast.matched[i] = self._evaluate(token, vrs)
return self._evaluate(ast, vrs)
else:
if ast.matched[0].name == 'IDT':
return self._evaluate(copy.deepcopy(vrs[ast.matched[0].value]), vrs)

else:
# At this point, ast.name will _always_ be `num`.
return calc_map[ast.name](ast.matched)

def infix(self) -> str:
Expand All @@ -95,10 +92,9 @@ def __str__(self):
return self._str(self.ast) # + '\n>> ' + self.infix()

def _str(self, ast, depth=0) -> str:
output = (('\t' * depth) + ast.name) + '\n'
output = (('\t' * depth) + ast.name + ' = ' + str(ast.value.value)) + '\n'

for matched in ast.matched:
# print('**matched', matched)
if isinstance(matched, RuleMatch) and matched.matched:
output += self._str(matched, depth + 1)

Expand Down
5 changes: 3 additions & 2 deletions calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ def evaluate(self, eqtn: str) -> Value:
raise Exception('Invalid equation (bad format)')

ast = Ast(root)
print(ast)
res = ast.evaluate(self.vrs)

if isinstance(res, Value):
ast.ast.value = res
print(ast)
return res

elif isinstance(res, dict):
Expand Down Expand Up @@ -65,5 +66,5 @@ def _match(self, tokens: List[Token], target_rule: str):
matched.append(m)
else:
# Success!
return RuleMatch(target_rule, matched), remaining_tokens
return RuleMatch(target_rule, matched, None), remaining_tokens
return None, None
24 changes: 20 additions & 4 deletions common.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,24 @@

from collections import namedtuple, OrderedDict
from enum import Enum
from typing import List

Token = namedtuple('Token', ('name', 'value'))
RuleMatch = namedtuple('RuleMatch', ('name', 'matched'))
Value = namedtuple('Value', ('type', 'value'))


class RuleMatch:
def __init__(self, name: str, matched: List[Token], value: Value = None):
self.name = name
self.matched = matched
self.value = value

def __str__(self):
return 'RuleMatch(' + ', '.join(map(str, [self.name, self.matched, self.value])) + ')'

def __repr__(self):
return str(self)


token_map = OrderedDict((
(r'\d+(?:\.\d+)?', 'NUM'),
Expand Down Expand Up @@ -55,10 +70,11 @@
class Type(Enum):
Number = 0
Matrix = 1
MatrixRow = 2


Value = namedtuple('Value', ('type', 'value'))
value_map = {
'NUM': Type.Number,
'MAT': Type.Matrix
}
'MAT': Type.Matrix,
'MRW': Type.MatrixRow
}
44 changes: 24 additions & 20 deletions rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,49 @@
This file contains methods to handle calculation of all the rules.
"""
import math
from typing import List
import operator
from typing import List, Union

from common import Token
from common import Token, Value, Type, RuleMatch


def add(tokens: List[Token]) -> Token:
return Token('NUM', float(tokens[0].value) + float(tokens[2].value) if tokens[1].value == '+' else float(tokens[0].value) - float(tokens[2].value))
def add(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.Number, {'+': operator.add, '-': operator.sub}[tokens[1].value](tokens[0].value.value, tokens[2].value.value))


def mul(tokens: List[Token]) -> Token:
return Token('NUM', float(tokens[0].value) * float(tokens[2].value) if tokens[1].value == '*' else float(tokens[0].value) / float(tokens[2].value) if tokens[1].value == '/' else float(tokens[0].value) % float(tokens[2].value))
def mul(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.Number, {'*': operator.mul, '/': operator.truediv, '%': operator.mod}[tokens[1].value](tokens[0].value.value, tokens[2].value.value))


def pow(tokens: List[Token]) -> Token:
return Token('NUM', float(tokens[0].value) ** float(tokens[2].value))
def pow(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.Number, tokens[0].value.value ** tokens[2].value.value)


def opr(tokens: List[Token]) -> Token:
return Token('NUM', {'sqrt': math.sqrt, 'exp': math.exp, 'det': det}[tokens[0].value](tokens[1].value))
def opr(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.Number, {'sqrt': math.sqrt, 'exp': math.exp, 'det': det}[tokens[0].value](tokens[1].value.value))


def neg(tokens: List[Token]) -> Token:
return Token('NUM', float(tokens[1].value) if tokens[0].value == '+' else -float(tokens[1].value))
def neg(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.Number, tokens[1].value.value if tokens[0].value == '+' else -tokens[1].value.value)


def num(tokens: List[Token]) -> Token:
return Token('NUM', float(tokens[0].value))
def num(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
if isinstance(tokens[0], RuleMatch):
return tokens[0].value

return Value(Type.Number, float(tokens[0].value))

def mrw(tokens: List[Token]) -> Token:
return Token('MRW', list(map(lambda t: float(t.value), tokens)))

def mrw(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.MatrixRow, list(map(lambda t: t.value.value, tokens)))

def mbd(tokens: List[Token]) -> Token:
return Token('MAT', list(map(lambda t: t.value, tokens)))

def mbd(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return Value(Type.Matrix, list(map(lambda t: t.value.value, tokens)))

def mat(tokens: List[Token]) -> Token:
return tokens[0]

def mat(tokens: List[Union[Token, Value, RuleMatch]]) -> Value:
return tokens[0].value


def det(matrix: List[List[float]]) -> float:
Expand Down
2 changes: 1 addition & 1 deletion tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def evaluate(eqtn: str):
print(eqtn)
calc = Calculator()
res = calc.evaluate(eqtn)
print(res)
print(res, '\n' + '-' * 50)
return res.value


Expand Down

0 comments on commit 6c94d11

Please sign in to comment.