diff --git a/Tests/test_abacus.py b/Tests/test_abacus.py
new file mode 100644
index 0000000..cfd9a45
--- /dev/null
+++ b/Tests/test_abacus.py
@@ -0,0 +1,22 @@
+import unittest
+from abacus import Abacus
+
+class AbacusTest(unittest.TestCase):
+
+ def setUp(self):
+ self.ab = Abacus()
+ self.ab.set_var('code with', 20)
+
+ def test_var_assignment(self):
+ input_string = 'funk=(5+5)/2'
+ input_string = Abacus.clean_input(input_string)
+ chunks = Abacus.split_chunks(input_string)
+ Abacus.validate_chunks(chunks)
+ comment = Abacus.get_comment_from_chunks(chunks)
+ chunks_wo_comment = Abacus.get_chunks_without_comment(chunks)
+
+ chunks_wo = self.ab.process_chunks(chunks_wo_comment)
+ var, chunks_wo_var = Abacus.get_var_assignment_from_chunks(chunks_wo_comment)
+ if var is not None:
+ res = Abacus.calculate(''.join(chunks_wo_var))
+ self.ab.set_var(var, res)
\ No newline at end of file
diff --git a/abacus.py b/abacus.py
new file mode 100644
index 0000000..8d06db8
--- /dev/null
+++ b/abacus.py
@@ -0,0 +1,270 @@
+import mathematik
+
+
+class AbacusMultipleAssignmentException(Exception):
+ pass
+
+class AbacusNameAssignmentException(Exception):
+ pass
+
+class AbacusWrongAssignmentException(Exception):
+ pass
+
+class AbacusEmptyAssignmentException(Exception):
+ pass
+
+class AbacusDataModel:
+ step_no = 0
+ def __init__(self, input_string, chunks, chunks_values, value, comment, step_no=None):
+ self._input_string = input_string
+ self._chunks = chunks
+ self._chunks_values = chunks_values
+ self._value = value
+ self._comment = comment
+ if step_no is not None:
+ self._step_no = step_no
+ else:
+ self._step_no = AbacusDataModel._get_next_step_no()
+
+ @classmethod
+ def _get_next_step_no(cls):
+ cls.step_no += 1
+ return cls.step_no
+
+ @property
+ def value(self):
+ return self._value
+
+ @property
+ def input_string(self):
+ return self._input_string
+
+ @property
+ def chunks(self):
+ return self._chunks
+
+ @property
+ def chunks_values(self):
+ return self._chunks_values
+
+ @property
+ def comment(self):
+ return self._comment
+
+ def __repr__(self):
+ return self._step_no, self._input_string, str(self._chunks), str(self._chunks_values), self._value, self._comment
+
+
+
+class Abacus:
+ stop_operators = [':', '=']
+ operators = ['+', '-', '*', '/', ',']
+ brackets = ['(', ')']
+ comment = '#'
+ math_operator = '>'
+
+ def __init__(self):
+ self._vars = {'result': '0', 'cba': 'result+20+add'}
+ self._formel = {'add': 'result+10', 'abc': 'cba-result'} # dict()
+
+ def get_vars(self):
+ return self._vars
+
+
+
+ def get_var_by_name(self, name):
+ return self._vars.get(name, None)
+
+ def get_formel_by_name(self, name):
+ return self._formel.get(name, None)
+
+ def set_var(self, name, value):
+ if name in Abacus.stop_operators or name in Abacus.operators or name in Abacus.comment or name in Abacus.brackets:
+ raise AbacusNameAssignmentException('Name cannot be a operator')
+ res = self.get_formel_by_name(name)
+ if res:
+ raise AbacusNameAssignmentException('Name {} already exists'.format(name))
+ self._vars[name] = str(value)
+
+ def set_formel(self, name, value):
+ if name in Abacus.stop_operators or name in Abacus.operators or name in Abacus.comment or name in Abacus.brackets:
+ raise AbacusNameAssignmentException('Name cannot be a operator')
+ res = self.get_var_by_name(name)
+ if res:
+ raise AbacusNameAssignmentException('Name {} already exists'.format(name))
+ self._formel[name] = str(value)
+
+
+ @classmethod
+ def calculate(cls, input_string):
+ try:
+ return eval(input_string)
+ except Exception as e:
+ return e
+
+ @classmethod
+ def clean_input(cls, input_string):
+ input_string = str(input_string)
+ # input_string = input_string.replace(' ', '')
+ # input_string = input_string.replace('.', '')
+ input_string = input_string.replace(',', '.')
+ input_string = input_string.replace(';', ',')
+ return input_string.strip()
+
+
+ @classmethod
+ def split_chunks(cls, input_string):
+ chunks = list()
+ last_pos = 0
+ cnt_stop = 0
+ for i, c in enumerate(input_string):
+ if c == cls.comment:
+ if last_pos != i:
+ chunks.append(input_string[last_pos:i].strip())
+ chunks.append(input_string[i:].strip())
+ return chunks
+ if c in cls.stop_operators and cnt_stop == 0:
+ chunks.append(input_string[last_pos:i].strip())
+ chunks.append(input_string[i])
+ last_pos = i+1
+ cnt_stop += 1
+ elif c in cls.stop_operators and cnt_stop > 0:
+ raise AbacusMultipleAssignmentException('Multiple assignments not supported')
+
+ if c in cls.operators or c in cls.brackets:
+ if i != last_pos:
+ chunks.append(input_string[last_pos:i].strip())
+ chunks.append(input_string[i].strip())
+ last_pos = i+1
+ elif i == len(input_string)-1: # das letzte zeichen
+ chunks.append(input_string[last_pos:i+1].strip())
+ return chunks
+
+ @classmethod
+ def validate_chunks(cls, chunks):
+ input_str = ''.join(chunks)
+ if input_str[-1] in cls.operators:
+ raise AbacusWrongAssignmentException('Last character cannot be a operator')
+ for i, chunk in enumerate(chunks):
+ if chunk in cls.stop_operators and i != 1:
+ raise AbacusWrongAssignmentException('Wrong assignment expression')
+
+ @classmethod
+ def replace_operator_to_math(cls, input_string):
+ return input_string.replace(cls.math_operator, 'mathematik.')
+
+
+ def process_chunks(self, chunks):
+ chunks = chunks[:]
+ for i, chunk in enumerate(chunks):
+ res = self.get_var_by_name(chunk)
+ if res is not None:
+ chunks[i] = res
+ else:
+ res = self.get_formel_by_name(chunk)
+ if res is not None:
+ cchunks = Abacus.split_chunks(res)
+ res_var = self.process_chunks(cchunks)
+ for i in res_var:
+ chunks.insert()[i] = res_var # TODO: Unboxing die Liste und integration in die bestehende
+
+ return chunks
+
+ def _replace_formel_and_vars(self, input_str):
+ chunks = Abacus.split_chunks(input_str)
+ for i, chunk in enumerate(chunks):
+ res = self.get_var_by_name(chunk)
+ if res is not None:
+ chunks[i] = self._replace_formel_and_vars(res)
+ else:
+ res = self.get_formel_by_name(chunk)
+ if res is not None:
+ chunks[i] = self._replace_formel_and_vars(res)
+ return ''.join(chunks)
+
+
+
+ def process_input(self, input_str):
+ input_string = Abacus.clean_input(input_str)
+ input_string = self.replace_operator_to_math(input_string)
+ if len(input_string) == 0:
+ raise AbacusEmptyAssignmentException('Empty assignment expression')
+ chunks = Abacus.split_chunks(input_string)
+ comment, chunks = Abacus.get_comment_and_rest(chunks)
+ Abacus.validate_chunks(chunks)
+ formel, var_chunks = Abacus.get_function_assignment_from_chunks(chunks)
+ if formel is not None:
+ self.set_formel(formel, ''.join(var_chunks))
+ clean_chunks = self._replace_formel_and_vars(''.join(var_chunks))
+ value = Abacus.calculate(clean_chunks)
+ return input_string, chunks, clean_chunks, value, comment
+ else:
+ var, formel_chunks = Abacus.get_var_assignment_from_chunks(chunks)
+ if var is not None:
+ self.set_var(var, ''.join(formel_chunks))
+ clean_chunks = self._replace_formel_and_vars(''.join(formel_chunks))
+ value = Abacus.calculate(clean_chunks)
+ return input_string, chunks, clean_chunks, value, comment
+ else:
+ clean_chunks = self._replace_formel_and_vars(''.join(chunks))
+ value = Abacus.calculate(clean_chunks)
+ return input_string, chunks, clean_chunks, value, comment
+
+
+ @classmethod
+ def get_var_assignment_from_chunks(cls, chunks):
+ chunks = chunks[:]
+ chunks = ''.join(chunks).split(cls.stop_operators[1])
+ if len(chunks) > 2:
+ raise AbacusMultipleAssignmentException('Multiple assignments not supported')
+ if len(chunks) == 2:
+ return chunks[0], chunks[1:]
+ return None, None
+
+ @classmethod
+ def get_function_assignment_from_chunks(cls, chunks):
+ chunks = chunks[:]
+ chunks = ''.join(chunks).split(cls.stop_operators[0])
+ if len(chunks) > 2:
+ raise AbacusMultipleAssignmentException('Multiple assignments not supported')
+ if len(chunks) == 2:
+ return chunks[0], chunks[1:]
+ return None, None
+
+ @classmethod
+ def get_comment_from_chunks(cls, chunks):
+ for chunk in chunks:
+ chunk = str(chunk)
+ if chunk.startswith(cls.comment):
+ chunk = chunk[1:]
+ return chunk.strip()
+ return None
+
+ @classmethod
+ def get_chunks_without_comment(cls, chunks):
+ for i, chunk in enumerate(chunks):
+ chunk = str(chunk)
+ if chunk.startswith(cls.comment):
+ return chunks[:i]
+ return chunks
+
+ @classmethod
+ def get_comment_and_rest(cls, chunks):
+ comment = cls.get_comment_from_chunks(chunks)
+ rest = cls.get_chunks_without_comment(chunks)
+ return comment, rest
+
+
+if __name__ == '__main__':
+ input_string = ['10+5', 'bbc:(10+10)', 'bba=(bbc+20)', 'bba//bbc']
+ steps = list()
+ ab = Abacus()
+
+ for i_s in input_string:
+ res = ab.process_input(i_s)
+ adm = AbacusDataModel(*res)
+ steps.append(adm)
+
+ for s in steps:
+ s.__repr__()
+
diff --git a/abacus_core.py b/abacus_core.py
index ae2a203..bdbfcf8 100644
--- a/abacus_core.py
+++ b/abacus_core.py
@@ -4,7 +4,7 @@
class AbacusCore:
def __init__(self):
- self._input_string = input
+ self._input_string = ""
self._vars = dict()
self._funcs = dict()
diff --git a/gui.ui b/gui.ui
index 01420fb..d8ac188 100644
--- a/gui.ui
+++ b/gui.ui
@@ -15,6 +15,20 @@
+ -
+
+
-
+
+
+ -
+
+
+ Rechne!
+
+
+
+
+
-
-
@@ -122,20 +136,6 @@
- -
-
-
-
-
-
- -
-
-
- Rechne!
-
-
-
-
-