calculator: add prefix parser
This commit is contained in:
parent
220e70ab33
commit
425733deca
|
@ -1 +1,2 @@
|
||||||
from .postfix import parse_postfix
|
from .postfix import parse_postfix
|
||||||
|
from .prefix import parse_prefix
|
||||||
|
|
34
calculator/calculator/parse/prefix.py
Normal file
34
calculator/calculator/parse/prefix.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING, List, Union, cast
|
||||||
|
|
||||||
|
from calculator.ast import BinOp, Constant, UnaryOp
|
||||||
|
from calculator.core import operations
|
||||||
|
|
||||||
|
from .parsed_string import ParsedString
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from calculator.ast import Node
|
||||||
|
|
||||||
|
|
||||||
|
def queue_to_tree(q: List[Union[int, str]]) -> Node:
|
||||||
|
top = q.pop(0)
|
||||||
|
if type(top) is int:
|
||||||
|
return Constant(top)
|
||||||
|
top = cast(str, top)
|
||||||
|
if top == "@":
|
||||||
|
rhs = queue_to_tree(q)
|
||||||
|
return UnaryOp(operations.negate, rhs)
|
||||||
|
lhs = queue_to_tree(q)
|
||||||
|
rhs = queue_to_tree(q)
|
||||||
|
return BinOp(operations.STR_TO_BIN[top], lhs, rhs)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_prefix(input: str) -> Node:
|
||||||
|
"""
|
||||||
|
Parses the given string in prefix notation.
|
||||||
|
Negation is represented by the '@' sign.
|
||||||
|
"""
|
||||||
|
parsed = ParsedString(input).tokenize()
|
||||||
|
ans = queue_to_tree(parsed)
|
||||||
|
return ans
|
30
calculator/calculator/parse/test_prefix.py
Normal file
30
calculator/calculator/parse/test_prefix.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
from calculator.ast import BinOp, Constant, UnaryOp
|
||||||
|
from calculator.core import operations
|
||||||
|
|
||||||
|
from .prefix import parse_prefix
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_constant():
|
||||||
|
assert parse_prefix("42") == Constant(42)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_negated_constant():
|
||||||
|
assert parse_prefix("@ 42") == UnaryOp(operations.negate, Constant(42))
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_doubly_negated_constant():
|
||||||
|
assert parse_prefix("@@42") == UnaryOp(
|
||||||
|
operations.negate, UnaryOp(operations.negate, Constant(42))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_binary_operation():
|
||||||
|
assert parse_prefix("+ 12 27") == BinOp(operations.plus, Constant(12), Constant(27))
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_complete_expression_tree():
|
||||||
|
assert parse_prefix("*+12 27-42 51") == BinOp(
|
||||||
|
operations.times,
|
||||||
|
BinOp(operations.plus, Constant(12), Constant(27)),
|
||||||
|
BinOp(operations.minus, Constant(42), Constant(51)),
|
||||||
|
)
|
Loading…
Reference in a new issue