import math
import operator
import re
import subprocess

class Calculator:
	"""A postfix calculator engine."""
	opers = [
		{ # no operands
			"e": math.e, "pi": math.pi, "i": lambda: 1j
		},
		{ # 1 operand
			"~": lambda x: ~x, "sqrt": math.sqrt, "ln": math.log, "log": math.log10,
			"sin": math.sin, "cos": math.cos, "tan": math.tan, "exp": math.exp,
			"asin": math.asin, "acos": math.acos, "atan": math.atan,
			"rad": math.radians, "deg": math.degrees, "floor": math.floor,
			"ceil": math.ceil, "abs": math.fabs, "!": math.factorial,
			"1/x": lambda x: 1/x, "inv": lambda x: 1/x,
		},
		{ # 2 operands
			"+": operator.add, "-": operator.sub, "*": operator.mul,
			"/": operator.truediv, "\\": operator.floordiv, "%": operator.mod,
			"**": operator.pow, "^": operator.xor, "&": operator.and_,
			"|": operator.or_,
		}
	]
	bases = {"b": 2, "o": 8, "h": 16}

	def __init__(self):
		self.stack = []

	def calc(self, expr):
		for token in expr.split():
			if token in self.opers[0]:
				self.stack.append(self.opers[0][token]())
			elif token in self.opers[1]:
				self.stack.append(self.opers[1][token](self.stack.pop()))
			elif token in self.opers[2]:
				self.stack[-2:] = [self.opers[2][token](*self.stack[-2:])]
			else:
				try:
					val = None
					if token[-1] in "boh":
						val = int(token[:-1], self.bases[token[-1]])
					else:
						val = float(token)
					self.stack.append(val)
				except ValueError:
					pass

class CalcModule:
	require = "cmd"

	def __init__(self, circa):
		self.circa = circa
		self.contexts = {}

		self.events = {
			"cmd.dc": [self.dc],
			"cmd.dc!": [self.dc1]
		}
		self.docs = {
			"dc": "dc <expression> → execute the expression as a 'dc' command and print the result",
			"dc!": "dc! <expression> → execute the expression as a 'dc' command"
		}
	
	def dc(self, fr, to, expr, m):
		expr = re.sub(r"-([0-9])", r"_\1", expr)
		self.dc1(fr, to, expr + " p")

	def dc1(self, fr, to, expr, m):
		if to not in self.contexts:
			self.contexts[to] = None
		expr = re.sub(r"\b_\b", str(self.contexts[to]), expr)
		expr += "q\n"
		self.contexts[to] = str(subprocess.check_output(["dc", "-"],
			input=bytes(expr, "utf-8"), stderr=subprocess.STDOUT), "utf-8")
		self.circa.say(to, str(self.contexts[to]))

module = CalcModule

@@ -825,16 +825,67 @@
 %0A%09%09%7D%0A%09%5D%0A
+%09opers_ = %7B%0A%09%09%22_%22: lambda self: self.stack%5B-1%5D,%0A%09%7D%0A
 %09bases =
@@ -1269,16 +1269,94 @@
 %5B-2:%5D)%5D%0A
+%09%09%09elif token in self.opers_:%0A%09%09%09%09self.stack.append(self.opers_%5Btoken%5D(self))%0A
 %09%09%09else:

implement stack-related operators