summaryrefslogtreecommitdiff
path: root/gerberex/am_expression.py
diff options
context:
space:
mode:
Diffstat (limited to 'gerberex/am_expression.py')
-rw-r--r--gerberex/am_expression.py184
1 files changed, 184 insertions, 0 deletions
diff --git a/gerberex/am_expression.py b/gerberex/am_expression.py
new file mode 100644
index 0000000..f43ba2e
--- /dev/null
+++ b/gerberex/am_expression.py
@@ -0,0 +1,184 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2019 Hiroshi Murayama <opiopan@gmail.com>
+
+from gerber.utils import *
+from gerber.am_eval import OpCode
+from gerber.am_statements import *
+
+class AMExpression(object):
+ CONSTANT = 1
+ VARIABLE = 2
+ OPERATOR = 3
+
+ def __init__(self, kind):
+ self.kind = kind
+
+ @property
+ def value(self):
+ return self
+
+ def optimize(self):
+ pass
+
+ def to_inch(self):
+ return AMOperatorExpression(AMOperatorExpression.DIV, self,
+ AMConstantExpression(MILLIMETERS_PER_INCH))
+
+ def to_metric(self):
+ return AMOperatorExpression(AMOperatorExpression.MUL, self,
+ AMConstantExpression(MILLIMETERS_PER_INCH))
+
+ def to_gerber(self, settings=None):
+ pass
+
+ def to_instructions(self):
+ pass
+
+class AMConstantExpression(AMExpression):
+ def __init__(self, value):
+ super(AMConstantExpression, self).__init__(AMExpression.CONSTANT)
+ self._value = value
+
+ @property
+ def value(self):
+ return self._value
+
+ def optimize(self):
+ return self
+
+ def to_gerber(self, settings=None):
+ if isinstance(self._value, str):
+ return self._value
+ gerber = '%.6g' % self._value
+ return '%.6f' % self._value if 'e' in gerber else gerber
+
+ def to_instructions(self):
+ return [(OpCode.PUSH, self._value)]
+
+class AMVariableExpression(AMExpression):
+ def __init__(self, number):
+ super(AMVariableExpression, self).__init__(AMExpression.VARIABLE)
+ self.number = number
+
+ def optimize(self):
+ return self
+
+ def to_gerber(self, settings=None):
+ return '$%d' % self.number
+
+ def to_instructions(self):
+ return (OpCode.LOAD, self.number)
+
+class AMOperatorExpression(AMExpression):
+ ADD = '+'
+ SUB = '-'
+ MUL = 'X'
+ DIV = '/'
+
+ def __init__(self, op, lvalue, rvalue):
+ super(AMOperatorExpression, self).__init__(AMExpression.OPERATOR)
+ self.op = op
+ self.lvalue = lvalue
+ self.rvalue = rvalue
+
+ def optimize(self):
+ self.lvalue = self.lvalue.optimize()
+ self.rvalue = self.rvalue.optimize()
+
+ if isinstance(self.lvalue, AMConstantExpression) and isinstance(self.rvalue, AMConstantExpression):
+ lvalue = float(self.lvalue.value)
+ rvalue = float(self.rvalue.value)
+ value = lvalue + rvalue if self.op == self.ADD else \
+ lvalue - rvalue if self.op == self.SUB else \
+ lvalue * rvalue if self.op == self.MUL else \
+ lvalue / rvalue if self.op == self.DIV else None
+ return AMConstantExpression(value)
+ elif self.op == self.ADD:
+ if self.rvalue.value == 0:
+ return self.lvalue
+ elif self.lvalue.value == 0:
+ return self.rvalue
+ elif self.op == self.SUB:
+ if self.rvalue.value == 0:
+ return self.lvalue
+ elif self.lvalue.value == 0 and isinstance(self.rvalue, AMConstantExpression):
+ return AMConstantExpression(-self.rvalue.value)
+ elif self.op == self.MUL:
+ if self.rvalue.value == 1:
+ return self.lvalue
+ elif self.lvalue.value == 1:
+ return self.rvalue
+ elif self.lvalue == 0 or self.rvalue == 0:
+ return AMConstantExpression(0)
+ elif self.op == self.DIV:
+ if self.rvalue.value == 1:
+ return self.lvalue
+ elif self.lvalue.value == 0:
+ return AMConstantExpression(0)
+
+ return self
+
+ def to_gerber(self, settings=None):
+ return '(%s)%s(%s)' % (self.lvalue.to_gerber(settings), self.op, self.rvalue.to_gerber(settings))
+
+ def to_instructions(self):
+ for i in self.lvalue.to_instructions():
+ yield i
+ for i in self.rvalue.to_instructions():
+ yield i
+ op = OpCode.ADD if self.op == self.ADD else\
+ OpCode.SUB if self.op == self.SUB else\
+ OpCode.MUL if self.op == self.MUL else\
+ OpCode.DIV
+ yield (op, None)
+
+def eval_macro(instructions):
+ stack = []
+
+ def pop():
+ return stack.pop()
+
+ def push(op):
+ stack.append(op)
+
+ def top():
+ return stack[-1]
+
+ def empty():
+ return len(stack) == 0
+
+ for opcode, argument in instructions:
+ if opcode == OpCode.PUSH:
+ push(AMConstantExpression(argument))
+
+ elif opcode == OpCode.LOAD:
+ push(AMVariableExpression(argument))
+
+ elif opcode == OpCode.STORE:
+ yield (-argument, [pop()])
+
+ elif opcode == OpCode.ADD:
+ op1 = pop()
+ op2 = pop()
+ push(AMOperatorExpression(AMOperatorExpression.ADD, op2, op1))
+
+ elif opcode == OpCode.SUB:
+ op1 = pop()
+ op2 = pop()
+ push(AMOperatorExpression(AMOperatorExpression.SUB, op2, op1))
+
+ elif opcode == OpCode.MUL:
+ op1 = pop()
+ op2 = pop()
+ push(AMOperatorExpression(AMOperatorExpression.MUL, op2, op1))
+
+ elif opcode == OpCode.DIV:
+ op1 = pop()
+ op2 = pop()
+ push(AMOperatorExpression(AMOperatorExpression.DIV, op2, op1))
+
+ elif opcode == OpCode.PRIM:
+ yield (argument, stack)
+ stack = []