diff --git a/adot_to_cpp.py b/adot_to_cpp.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f185b2bdcadd912617e36f0a1b7399641b0a869
--- /dev/null
+++ b/adot_to_cpp.py
@@ -0,0 +1,18 @@
+import unittest
+from copy import deepcopy
+import subprocess
+import os
+import random
+import sys
+from test_funcs.simplest import * 
+import comsdk.parser as pars
+from comsdk.graph import *
+from comsdk.edge import Edge
+
+prsr = pars.Parser(tocpp=True)
+data = {"a":10, "b":0}
+gr = prsr.parse_file(sys.argv[1])
+if sys.argv[2] !="":
+    prsr.generate_cpp(sys.argv[2])
+else:
+    prsr.generate_cpp()
diff --git a/templates/.gitignore b/comsdk/__init__.py
similarity index 100%
rename from templates/.gitignore
rename to comsdk/__init__.py
diff --git a/comsdk/__pycache__/__init__.cpython-37.pyc b/comsdk/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f9404d7651af084fa1904c30f3f2177d136df94d
Binary files /dev/null and b/comsdk/__pycache__/__init__.cpython-37.pyc differ
diff --git a/comsdk/__pycache__/comaux.cpython-37.pyc b/comsdk/__pycache__/comaux.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4542f51de64a0b77ce8e354a8bd8e1474687a982
Binary files /dev/null and b/comsdk/__pycache__/comaux.cpython-37.pyc differ
diff --git a/comsdk/__pycache__/communication.cpython-37.pyc b/comsdk/__pycache__/communication.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4d27064eec3908f8312c68db10e8c3e042a0505e
Binary files /dev/null and b/comsdk/__pycache__/communication.cpython-37.pyc differ
diff --git a/comsdk/__pycache__/edge.cpython-37.pyc b/comsdk/__pycache__/edge.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9fc9d7bc448ba0ff4d69489503373000e4f03660
Binary files /dev/null and b/comsdk/__pycache__/edge.cpython-37.pyc differ
diff --git a/comsdk/__pycache__/graph.cpython-37.pyc b/comsdk/__pycache__/graph.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d26ff4d7ad63377bfc86d9c384514df6ae83d68d
Binary files /dev/null and b/comsdk/__pycache__/graph.cpython-37.pyc differ
diff --git a/comsdk/__pycache__/parser.cpython-37.pyc b/comsdk/__pycache__/parser.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2af755407ceeea4d4b4325fc67d619ef32e898c6
Binary files /dev/null and b/comsdk/__pycache__/parser.cpython-37.pyc differ
diff --git a/comsdk/aux.py b/comsdk/comaux.py
similarity index 100%
rename from comsdk/aux.py
rename to comsdk/comaux.py
diff --git a/comsdk/communication.py b/comsdk/communication.py
index a25dd50b238fb2580d0ec18b8bf54f1d11bb2949..1c45001ba28b168e82ed42c20928f8b3f43cb036 100644
--- a/comsdk/communication.py
+++ b/comsdk/communication.py
@@ -8,7 +8,7 @@ import json
 from stat import S_ISDIR
 from abc import ABCMeta, abstractmethod
 
-from comsdk.aux import load_function_from_module
+from comsdk.comaux import load_function_from_module
 
 class Host(object):
     '''
diff --git a/comsdk/distributed_storage.py b/comsdk/distributed_storage.py
index f2fec11624bf29521f5dd5a9939e4214266457dd..0d7667dc33d067f551b92ae33ad2bd203064b5ad 100644
--- a/comsdk/distributed_storage.py
+++ b/comsdk/distributed_storage.py
@@ -1,4 +1,4 @@
-from comsdk.aux import find_dir_by_named_regexp
+from comsdk.comaux import find_dir_by_named_regexp
 from functools import partial
 import os
 
diff --git a/comsdk/edge.py b/comsdk/edge.py
index 36cbe9a3fcad5416fc14a6d2ee75579849f8d35e..66a9b0f74592320ff1ff83e6cc71598ab2898df5 100644
--- a/comsdk/edge.py
+++ b/comsdk/edge.py
@@ -1,5 +1,6 @@
-import comsdk.aux as aux
+import comsdk.comaux as aux
 from comsdk.communication import CommunicationError
+from comsdk.graph import Func
 
 from mako.template import Template
 import os
@@ -26,43 +27,53 @@ class InOutMapping(object):
 
 class Edge(object):
     __slots__ = [
-        '_predicate', 
-        '_morphism',
+        'pred_f',
+        'morph_f',
         '_io_mapping',
         'preprocess',
         'postprocess',
-        ]
+        'order',
+        'comment'
+    ]
     def __init__(self, predicate, morphism, 
                  io_mapping=InOutMapping(),
+                 order=0, 
+                 comment=""
                  ):
-        self._predicate = predicate
-        self._morphism = morphism
+        self.pred_f = predicate
+        self.morph_f = morphism
         self._io_mapping = io_mapping
         self.preprocess = lambda pd: None
         self.postprocess = lambda pd: None
+        self.order = int(0 if order is None else order)
+        self.comment = comment
 
     def predicate(self, data, dynamic_keys_mapping={}):
         proxy_data = self._io_mapping.build_proxy_data(data, dynamic_keys_mapping)
-        return self._predicate(proxy_data)
+        return self.pred_f.func(proxy_data)
 
     def morph(self, data, dynamic_keys_mapping={}):
-        #print(dynamic_keys_mapping)
+        # print(self.pred_name, self.morph_name, self.order)
         proxy_data = self._io_mapping.build_proxy_data(data, dynamic_keys_mapping)
-        #print(proxy_data)
+        # print(proxy_data)
         self.preprocess(data)
-        self._morphism(proxy_data)
+        self.morph_f.func(proxy_data)
         self.postprocess(data)
+    
 
-class DummyEdge(Edge):
-    def __init__(self):
-        super().__init__(None, None)
+# class DummyEdge(Edge):
+    # def __init__(self):
+        # super().__init__(None, None)
+# 
+    # def predicate(self, data, dynamic_keys_mapping={}):
+        # return True
+# 
+    # def morph(self, data, dynamic_keys_mapping={}):
+        # self.preprocess(data)
+        # self.postprocess(data)
 
-    def predicate(self, data, dynamic_keys_mapping={}):
-        return True
-
-    def morph(self, data, dynamic_keys_mapping={}):
-        self.preprocess(data)
-        self.postprocess(data)
+def DummyEdge():
+    return Edge(Func(), Func())
 
 class ExecutableProgramEdge(Edge):
     '''
diff --git a/comsdk/graph.py b/comsdk/graph.py
index 08c2369a3733a4b9042e5b1cec897913ee5a5df2..c850991a54ff2b57c73e342ba49747f1e0e6c26b 100644
--- a/comsdk/graph.py
+++ b/comsdk/graph.py
@@ -2,59 +2,68 @@ import collections
 import os
 from enum import Enum, auto
 from functools import partial
+import importlib as imp
 
-import comsdk.aux as aux
+
+import comsdk.comaux as aux
 
 ImplicitParallelizationInfo = collections.namedtuple('ImplicitParallelizationInfo', ['array_keys_mapping', 'branches_number', 'branch_i'])
 
-class Morphism:
-    def __init__(self, edge, output_state):
+class Func():
+    __slots__ = (
+        'module',
+        'func',
+        'comment',
+        'name'
+    )
+    def __init__(self, module="", name="", dummy=False,func=None, comment=''):
+        self.module = module
+        self.name = name
+        self.comment=comment.replace("\0", " ") if comment is not None else ""
+        if module =="" or name =="" or module is None or name is None:
+            dummy = True
+        if func is not None:
+            self.func = func
+        elif dummy:
+            self.func = lambda data: data
+        else: 
+            print("LOADING function {} from {} module".format(name, module) )
+            try:
+                self.func = getattr(imp.import_module(module), name)
+            except Exception:
+                raise Exception("Could not load function {} from {} module".format(name, module))
+
+    def __str__(self):
+        if self.module =="" or self.name =="":
+            return ''
+        return "{}_{}".format(self.module, self.name)
+
+class Selector(Func):
+    def __init__(self, ntransf, module="", name="", dummy=False):
+        if module=="" and name =="":
+            dummy = True
+        self.dummy = dummy
+        super().__init__(module, name, func=(lambda x: [True for i in range(ntransf)]) if dummy else None)
+    def __str__(self):
+        if self.module =="" or self.name =="":
+            return ''
+        return "{}_{}".format(self.module, self.name)
+
+
+class Transfer:
+    def __init__(self, edge, output_state, order=0, comment = None):
         self.edge = edge
         self.output_state = output_state
+        self.order = order
 
-    def morph(self, data, dynamic_keys_mapping={}):
-        #print(dynamic_keys_mapping)
+    def transfer(self, data, dynamic_keys_mapping={}):
         self.edge.morph(data, dynamic_keys_mapping)
-        #return self.output_state, None
         return self.output_state
 
 class IdleRunType(Enum):
     INIT = auto()
     CLEANUP = auto()
 
-class GraphFactory:
-    def __init__(self):
-        pass
-
-    def create_state():
-        pass
-
-    def create_edge():
-        # Here we should somehow pass the argument for "special" edges
-        # Essentially, we change only io_mapping
-        pass
-
-    def make_graph():
-        pass
-
-class PluralGraphFactory:
-    def __init__(self, plural_keys_mappings, parallel_graphs_number):
-        self.plural_keys_mappings = plural_keys_mappings
-        self.parallel_graphs_number = parallel_graphs_number
-        self.init_state = None
-        
-    def create_state(state):
-        if self.init_state == None:
-            self.init_state = state
-
-    def create_edge():
-        # Here we should somehow pass the argument for "special" edges
-        # Essentially, we change only io_mapping
-        pass
-
-    def make_graph():
-        pass
-
 class PluralState:
     def __init__(self, states):
         self.states = states
@@ -62,7 +71,7 @@ class PluralState:
 
     def connect_to(self, term_states, edge):
         for init_state, term_state in zip(self.states, term_states):
-            init_state.output_morphisms.append(Morphism(edge, term_state))
+            init_state.transfers.append(Transfer(edge, term_state))
 
 class Graph:
     '''
@@ -93,18 +102,18 @@ class Graph:
         while cur_state is not None:
  #           print('1) In main loop', implicit_parallelization_info)
 #            morph = _run_state(cur_state, data, implicit_parallelization_info)
-            morph, implicit_parallelization_info = _run_state(cur_state, data, implicit_parallelization_info)
+            transfer_f, implicit_parallelization_info = _run_state(cur_state, data, implicit_parallelization_info)
 #            print('2) In main loop', implicit_parallelization_info)
             if '__EXCEPTION__' in data:
                 return False
 #            cur_state, implicit_parallelization_info = morph(data)
-            cur_state = morph(data)
+            cur_state = transfer_f(data)
 #            print(morph)
             if '__EXCEPTION__' in data:
                 return False
         return True
 
-    def init_graph(self, data):
+    def init_graph(self, data={}):
         if not self._initialized:
             self.init_state.idle_run(IdleRunType.INIT, [self.init_state.name])
             self._initialized = True
@@ -114,41 +123,53 @@ class Graph:
         if not '__WORKING_DIR__' in data:
             data['__WORKING_DIR__'] = data['__CURRENT_WORKING_DIR__']
 
+
+
+
 class State:
     __slots__ = [
         'name',
-        'input_edges_number',
+        'input_edges_number', #output_edges_number == len(transfers)
         'looped_edges_number',
         'activated_input_edges_number',
-        'output_morphisms',
+        'transfers',
         'parallelization_policy',
-        'selection_policy',
+        'selector',
         'is_term_state',
         'array_keys_mapping',
         '_branching_states_history',
         '_proxy_state',
+        'possible_branches',
+        'comment'
         ]
     def __init__(self, name, 
                  parallelization_policy=None,
-                 selection_policy=None,
+                 selector=None,
                  array_keys_mapping=None, # if array_keys_mapping is not None, we have implicit parallelization in this state
                  ):
         self.name = name
         self.parallelization_policy = SerialParallelizationPolicy() if parallelization_policy is None else parallelization_policy
-        self.selection_policy = OnlyOneSelectionPolicy() if selection_policy is None else selection_policy
+        self.selector = Selector(1) if selector is None else selector
         self.array_keys_mapping = array_keys_mapping
         self.input_edges_number = 0
         self.looped_edges_number = 0
         self.activated_input_edges_number = 0
-        self.output_morphisms = []
+        self.transfers = []
+        self.possible_branches=[]
         self.is_term_state=False
         self._branching_states_history = None
         self._proxy_state=None
+        self.comment = None
 
     def idle_run(self, idle_run_type, branching_states_history):
+        def __sort_by_order(tr):
+            return tr.edge.order
+        self.transfers.sort(key = __sort_by_order)
+        # print(self.name)
+        # for t in self.transfers:
+            # print("\t", t.edge.order, t.edge.pred_name, t.edge.morph_name)
         if self._proxy_state is not None:
             return self._proxy_state.idle_run(idle_run_type, branching_states_history)
-#        print('{} {} -> '.format(self.name, branching_states_history), end='')
         if idle_run_type == IdleRunType.INIT:
             self.input_edges_number += 1
             if self.input_edges_number != 1:
@@ -159,66 +180,66 @@ class State:
                 self._branching_states_history = branching_states_history
         elif idle_run_type == IdleRunType.CLEANUP:
             self.activated_input_edges_number = 0
-#           print('\tCLEANUP STATE {}, active: {}, branches_story: {}'.format(self.name, self.activated_input_edges_number, self._branching_states_history))
             if self._branching_states_history is not None and self._is_looped_branch(branching_states_history):
-#                print('\tqwer')
                 self._branching_states_history = None
                 return
             if self._branching_states_history is None:
                 self._branching_states_history = branching_states_history
         else:
             self.activated_input_edges_number += 1 # BUG: here we need to choose somehow whether we proceed or not
-#        if len(self.output_edges) == 0:
-#            print('Terminate state found')
-        if len(self.output_morphisms) == 1:
-            self.output_morphisms[0].output_state.idle_run(idle_run_type, branching_states_history)
+        # if len(self.transfers) == 0:
+            # print('Terminate state found')
+        if len(self.transfers) == 1:
+            self.transfers[0].output_state.idle_run(idle_run_type, branching_states_history)
         else:
-            for i, morphism in enumerate(self.output_morphisms):
-                next_state = morphism.output_state
+            for i, transfer in enumerate(self.transfers):
+                next_state = transfer.output_state
                 next_state.idle_run(idle_run_type, branching_states_history + [next_state.name])
 
-    def connect_to(self, term_state, edge):
-        self.output_morphisms.append(Morphism(edge, term_state))
+    def connect_to(self, term_state, edge=None, comment=None):
+        if comment is not None or comment != "":
+            self.comment = comment
+        self.transfers.append(Transfer(edge, term_state))
+        self.selector = Selector(len(self.transfers))
 #        edge.set_output_state(term_state)
 #        self.output_edges.append(edge)
 
     def replace_with_graph(self, graph):
         self._proxy_state = graph.init_state
-        graph.term_state.output_morphisms = self.output_morphisms
+        graph.term_state.transfers = self.transfers
+        graph.term_state.selector = self.selector
 
+    
     def run(self, data, implicit_parallelization_info=None):
-        print('STATE {}, just entered, implicit_parallelization_info: {}'.format(self.name, implicit_parallelization_info))
+        print('STATE {}\n\tjust entered, implicit_parallelization_info: {}'.format(self.name, implicit_parallelization_info))
+        # print('\t{}'.format(data))
         if self._proxy_state is not None:
             return self._proxy_state.run(data, implicit_parallelization_info)
         self._activate_input_edge(implicit_parallelization_info)
         #self.activated_input_edges_number += 1
-        print('STATE {}, required input: {}, active: {}, looped: {}'.format(self.name, self.input_edges_number, self.activated_input_edges_number, self.looped_edges_number))
+        print('\trequired input: {}, active: {}, looped: {}'.format(self.input_edges_number, self.activated_input_edges_number, self.looped_edges_number))
 #        print('qwer')
-        if not self._ready_to_morph(implicit_parallelization_info):
+        if not self._ready_to_transfer(implicit_parallelization_info):
             return None, None # it means that this state waits for some incoming edges (it is a point of collision of several edges)
         self._reset_activity(implicit_parallelization_info)
         if self.is_term_state:
             implicit_parallelization_info = None
-        #print(self.name)
-        if len(self.output_morphisms) == 0:
-            return morphism_to_termination, None
-        predicate_values = []
+        if len(self.transfers) == 0:
+            return transfer_to_termination, None
         dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info)
-        for morphism in self.output_morphisms:
-            predicate_values.append(morphism.edge.predicate(data, dynamic_keys_mapping))
-        selected_edge_indices = self.selection_policy.select(predicate_values)
-        if not selected_edge_indices:
+        selected_edges = self.selector.func(data)
+        if not selected_edges:
             raise GraphUnexpectedTermination(
-                'State {}: Predicate values {} do not conform selection policy'.format(self.name, predicate_values))
-        selected_morphisms = [self.output_morphisms[i] for i in selected_edge_indices]
-        return self.parallelization_policy.make_morphism(selected_morphisms,
+                "STATE {}: error in selector: {} ".format(self.name, selected_edges))
+        selected_transfers = [self.transfers[i] for i, _ in enumerate(selected_edges) if selected_edges[i]==True]
+        for transf in selected_transfers:
+            if not transf.edge.predicate(data, dynamic_keys_mapping):
+                raise Exception("\tERROR: predicate {} returns {} running from state {}\n data{}".format(transf.edge.pred_f.name,transf.edge.predicate(data, dynamic_keys_mapping), self.name, data))
+        return self.parallelization_policy.make_transfer_func(selected_transfers,
                                                          array_keys_mapping=self.array_keys_mapping,
-                                                         implicit_parallelization_info=implicit_parallelization_info,), \
+                                                         implicit_parallelization_info=implicit_parallelization_info, state=self), \
                implicit_parallelization_info
 
-#        return self.parallelization_policy.make_morphism(selected_morphisms,
-#                                                         array_keys_mapping=self.array_keys_mapping,
-#                                                         implicit_parallelization_info=implicit_parallelization_info,)
 
     def _activate_input_edge(self, implicit_parallelization_info=None):
         if implicit_parallelization_info is None or self.is_term_state:
@@ -228,7 +249,7 @@ class State:
                 self.activated_input_edges_number = [0 for i in range(implicit_parallelization_info.branches_number)]
             self.activated_input_edges_number[implicit_parallelization_info.branch_i] += 1
 
-    def _ready_to_morph(self, implicit_parallelization_info=None):
+    def _ready_to_transfer(self, implicit_parallelization_info=None):
         required_activated_input_edges_number = self.input_edges_number - self.looped_edges_number
         if implicit_parallelization_info is not None:
             if self.is_term_state:
@@ -247,7 +268,7 @@ class State:
 
     def _reset_activity(self, implicit_parallelization_info=None):
         self._branching_states_history = None
-        if self._ready_to_morph(implicit_parallelization_info) and self._has_loop():
+        if self._ready_to_transfer(implicit_parallelization_info) and self._has_loop():
             if implicit_parallelization_info is None or self.is_term_state:
                 self.activated_input_edges_number -= 1
             else:
@@ -265,7 +286,8 @@ class State:
     def _has_loop(self):
         return self.looped_edges_number != 0
 
-def morphism_to_termination(data):
+
+def transfer_to_termination(data):
     return None
 
 class SerialParallelizationPolicy:
@@ -274,59 +296,12 @@ class SerialParallelizationPolicy:
     def __init__(self):
         pass
 
-#    def make_morphism(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None):
-#        def _morph(data):
-#            if array_keys_mapping is None:
-#                dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info)
-#                next_morphs = [partial(morphism.morph, dynamic_keys_mapping=dynamic_keys_mapping) for morphism in morphisms]
-#                next_impl_para_infos = [implicit_parallelization_info for _ in morphisms]
-# #               print('\t\t {}'.format(implicit_parallelization_infos))
-#            else:
-#                if len(morphisms) != 1:
-#                    raise BadGraphStructure('Impossible to create implicit paralleilzation in the state with {} output edges'.format(len(morphisms)))
-#                dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info)
-#                proxy_data = aux.ProxyDict(data, keys_mappings=array_keys_mapping)
-#                anykey = next(iter(array_keys_mapping.keys()))
-#                implicit_branches_number = len(proxy_data[anykey])
-#                next_morphs = []
-#                next_impl_para_infos = []
-#                for branch_i in range(implicit_branches_number):
-#                    implicit_parallelization_info_ = ImplicitParallelizationInfo(array_keys_mapping, implicit_branches_number, branch_i)
-#                    dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info_)
-#                    next_morphs.append(partial(morphisms[0].morph, dynamic_keys_mapping=dynamic_keys_mapping))
-#                    next_impl_para_infos.append(implicit_parallelization_info_)
-#            cur_morphs = []
-#            cur_impl_para_infos = []
-#            while len(next_morphs) != 1:
-#                cur_morphs[:] = next_morphs[:]
-#                cur_impl_para_infos[:] = next_impl_para_infos[:]
-#                del next_morphs[:]
-#                del next_impl_para_infos[:]
-#                # WE DO NOT UPDATE implicit_parallelization_infos !!!
-#                for morph, impl_para_info in zip(cur_morphs, cur_impl_para_infos):
-#                    next_state, _ = morph(data)
-##                    print('\t next_state: {}, with impl para info: {}'.format(next_state.name, impl_para_info))
-#                    if next_state is None:
-#                        return None, None
-#                    next_morph = _run_state(next_state, data, impl_para_info)
-##                    print('\t next_morph: {}'.format(next_morph))
-#                    if '__EXCEPTION__' in data:
-#                        return None, None
-#                    if next_morph is not None:
-#                        next_morphs.append(next_morph)
-#                        next_impl_para_infos.append(impl_para_info)
-#                #print(len(next_morphs))
-##            print('\t last morph: {}'.format(next_morphs[0]))
-#            next_state, _ = next_morphs[0](data)
-#            print(next_state.name, next_impl_para_infos[0])
-#            return next_state, next_impl_para_infos[0]
-#        return _morph
-
-    def make_morphism(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None):
+    def make_transfer_func(self, morphisms, array_keys_mapping=None, implicit_parallelization_info=None, state=None):
         def _morph(data):
+            # print("MORPHING FROM {}".format(state.name))
             if array_keys_mapping is None:
                 dynamic_keys_mapping = build_dynamic_keys_mapping(implicit_parallelization_info)
-                next_morphs = [partial(morphism.morph, dynamic_keys_mapping=dynamic_keys_mapping) for morphism in morphisms]
+                next_morphs = [partial(morphism.transfer, dynamic_keys_mapping=dynamic_keys_mapping) for morphism in morphisms]
                 next_impl_para_infos = [implicit_parallelization_info for _ in morphisms]
  #               print('\t\t {}'.format(implicit_parallelization_infos))
             else:
@@ -349,7 +324,7 @@ class SerialParallelizationPolicy:
             #while len(next_morphs) != 1 or _is_implicitly_parallelized(next_impl_para_infos):
             while len(next_morphs) != 1 or _requires_joint_of_implicit_parallelization(array_keys_mapping, next_impl_para_infos):
                 if next_impl_para_infos == []:
-                    raise Exception(str(len(next_morphs)))
+                    raise Exception("Morphs count on state {} is {}".format(state.name, str(len(next_morphs))))
 #                print(array_keys_mapping, next_impl_para_infos)
                 cur_morphs[:] = next_morphs[:]
                 cur_impl_para_infos[:] = next_impl_para_infos[:]
@@ -376,26 +351,6 @@ class SerialParallelizationPolicy:
         return _morph
 
 
-class OnlyOneSelectionPolicy:
-    def __init__(self):
-        pass
-
-    def select(self, predicate_values):
-        trues_indices = _get_trues(predicate_values)
-        if len(trues_indices) != 1:
-            return None
-        return trues_indices
-
-class AllSelectionPolicy:
-    def __init__(self):
-        pass
-
-    def select(self, predicate_values):
-        trues_indices = _get_trues(predicate_values)
-        if len(trues_indices) != len(predicate_values):
-            return None
-        return trues_indices
-
 class BadGraphStructure(Exception):
     pass
 
diff --git a/comsdk/parser.py b/comsdk/parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..f264ac0cfa19d097e9cbae3440504c26f124a2ab
--- /dev/null
+++ b/comsdk/parser.py
@@ -0,0 +1,455 @@
+import re
+import copy
+import importlib as imp
+
+from comsdk.graph import Graph, Func, State, Selector
+from comsdk.edge import Edge
+
+
+class Params():
+    __slots__=(
+        'module',
+        'entry_func',
+        'predicate',
+        'selector',
+        'function',
+        'morphism',
+        'parallelism',
+        'comment',
+        'order',
+        'subgraph'
+    )
+    def __init__(self):
+        for slot in self.__slots__:
+            setattr(self, slot, None)
+    
+    def __str__(self):
+        stri = ""
+        for s in self.__slots__:
+            stri += ((s+": {}, ".format(getattr(self, s))) if getattr(self, s) is not None else "")
+        return stri
+
+# entities = {}
+
+class GraphFactory():
+    __slots__ = (
+        'name',
+        'states', 
+        'graph',
+        'issub',
+        'tocpp',
+        'entities'
+    )
+    def __init__(self, tocpp=False):
+        self.states = {}
+        self.entities = {}
+        self.tocpp = tocpp
+        self.name = None
+        self.issub = False
+
+    def add_state(self, statename):
+        if statename not in self.states:
+            self.states[statename] = State(statename)
+            if statename in self.entities:
+                self.states[statename].comment = self.entities[statename].comment
+    
+    def _create_morphism(self, morphname=None):
+        comment = ""
+        if morphname is None:
+            return Func(), Func(), comment
+        pred_f, func_f = Func(), Func() 
+        morph = self.entities[morphname]
+        for m in morph.__slots__:
+            if getattr(morph,m) is not None:
+                if m!="predicate" and m!="function" and m!="comment":
+                    raise Exception("ERROR: Morphisms could not have any params exept comment, predicate and function!\n{}".format(morphname))
+                if m=="comment":
+                    comment=getattr(morph, m).replace("\0", " ")
+                if m=="predicate":
+                    if getattr(morph,m) not in self.entities:
+                        raise Exception("\tERROR: Predicate {} is not defined!".format(getattr(morph, m)))
+                    pred = self.entities[getattr(morph, m)]
+                    if self.tocpp:
+                        pred_f = Func(pred.module, pred.entry_func, dummy=True, comment=pred.comment)
+                    else:
+                        pred_f = Func(pred.module, pred.entry_func, comment=pred.comment)
+                if m=="function":
+                    if getattr(morph,m) not in self.entities:
+                       raise Exception("\tERROR: Function: {} is not defined!".format(getattr(morph, m)))
+                    fu = self.entities[getattr(morph, m)]
+                    if self.tocpp:
+                        func_f = Func(fu.module, fu.entry_func, dummy=True, comment=fu.comment)
+                    else:
+                        func_f = Func(fu.module, fu.entry_func,comment=fu.comment)
+        return pred_f, func_f, comment
+
+
+    def add_connection(self, st1, st2, morphism=None, ordr=0):
+        pred, entr, comm = self._create_morphism(morphism)
+        self.states[st1].connect_to(self.states[st2], edge=Edge(pred, entr, order=ordr, comment=comm))
+        print("{} -> {}".format(st1, st2))
+
+    def build(self, nsub):
+        print("BUILDING {}\nStates:".format(self.name))
+        for s in self.states:
+            print("\t"+ s)
+        if self.issub:
+            self.graph = Graph(self.states[self.name+str(nsub)+"_"+"__BEGIN__"], self.states[self.name+str(nsub)+"_"+"__END__"])
+        else:    
+            self.graph = Graph(self.states["__BEGIN__"], self.states["__END__"])
+        self.graph.init_graph()
+        if self.issub:
+            oldkeys = []
+            for e in self.entities:
+                oldkeys.append(e)
+            for old in oldkeys:
+                if self.entities[old].selector is not None or self.entities[old].subgraph is not None:
+                    self.entities[self.name + str(Parser.subgr_count)+"_"+old] = self.entities[old]
+                    del self.entities[old] 
+        for s in self.states:
+            if s in self.entities and self.entities[s].selector is not None:
+                selname = self.entities[s].selector
+                if self.tocpp:
+                    self.states[s].selector = Selector(len(self.states[s].transfers), self.entities[selname].module, self.entities[selname].entry_func, dummy=True)
+                else:
+                    self.states[s].selector = Selector(len(self.states[s].transfers), self.entities[selname].module, self.entities[selname].entry_func)
+            else:
+                self.states[s].selector =  Selector(len(self.states[s].transfers))
+            if s in self.entities and self.entities[s].subgraph is not None:
+                print("Replacing state {} with subgraph {}".format(s,self.entities[s].subgraph))
+                parsr = Parser(subgraph=True, tocpp= self.tocpp)
+                subgr = parsr.parse_file(self.entities[s].subgraph)
+                self.states[s].replace_with_graph(subgr)
+                self.graph = Graph(self.graph.init_state, self.graph.term_state)
+        return self.graph
+
+
+class Parser():
+    __slots__ = (
+        'fact',
+        'issub'
+    )
+    subgr_count = 0
+    def __init__(self, tocpp=False, subgraph=False):
+        self.fact = GraphFactory(tocpp=tocpp)
+        self.fact.issub = subgraph
+        self.issub = subgraph
+        if subgraph:
+            Parser.subgr_count+=1
+    
+    def _check_brackets(self, rawfile):
+        br = { "[":{"line":0, "count":0}, "(":{"line":0, "count":0}, "{":{"line":0, "count":0}, "\"":{"line":0, "count":0}}
+        line = 1
+        qu = 0
+        for char in rawfile:
+            if char == "[":
+                br["["]["line"] = line
+                br["["]["count"] +=1 
+            elif char == "{":
+                br["{"]["line"] = line
+                br["{"]["count"] +=1 
+            elif char == "(":
+                br["("]["line"] = line
+                br["("]["count"] +=1 
+            elif char == "]":
+                br["["]["count"] -=1 
+            elif char == "}":
+                br["{"]["count"] -=1 
+            elif char == ")":
+                br["("]["count"] -=1 
+            elif char =="\"":
+                br["\""]["line"] = line
+                br["\""]["count"] += 1 if br["\""]["count"]==0 else -1
+            elif char == "\n":
+                line+=1
+        expstr= "Brackets or quotes do not match! Missing closing brackets on lines: "
+        fl = False
+        for c in br:
+            if br[c]["count"] != 0:
+                fl= True
+                expstr+=str(br[c]["line"])+" "
+        if fl:
+            raise Exception(expstr)
+
+    def _split_multiple(self,param):
+        vals = {}
+        first=True
+        for s in param.__slots__:
+            attr = getattr(param,s)
+            if attr is not None and '\0' in attr:
+                vals[s] = attr.split('\0')
+        l=0
+        for sl in vals:
+            if l==0:
+                l=len(vals[sl])
+            elif l!=len(vals[sl]):
+                raise Exception("\tERROR: Number of multiple params do not match", l)
+        res = [copy.copy(param) for i in range(l)]
+        for sl in vals:
+            for i, _ in enumerate(res):
+                setattr(res[i], sl, vals[sl][i])
+        return res
+
+    #Props is line "[proFp=smth, ...]"
+    def _param_from_props(self,props):
+        parm = Params()
+        comment = ""
+        if props =="":
+            return parm
+        props = props.replace("]", '')
+        if '\"' in props:
+            m = [m for m in re.finditer(r'\".*\"', props)][0]
+            comment = props[m.span()[0]+1:m.span()[1]-1]
+            props=props[:m.span()[0]]+props[m.span()[1]:]
+        if '(' in props:
+            mchs = [m for m in re.finditer(r'\((\w+,)*\w+\)', props)]
+            for m in mchs:
+                props=props[:m.span()[0]]+(props[m.span()[0]:m.span()[1]]).replace(',','\0')+props[m.span()[1]:]
+        props = props.replace("(","")
+        props = props.replace(")","")
+        rs =props.split(r",") #.split(r", ")
+        for r in rs:
+            r=r.split(r"=", 1)
+            if r[0] in parm.__slots__:
+                setattr(parm, r[0], r[1])
+            else:
+                raise Exception("\tERROR:Unknown parameter: "+ r[0])
+        if comment != "": 
+            setattr(parm, "comment", comment.replace("\0", " "))
+        return parm
+
+    def _param_from_entln(self, raw):
+        res = re.split(r"\[", raw, 1)
+        return res[0], self._param_from_props(res[1])
+
+    def _multiple_morphs(self,props, n):
+        p = self._param_from_props(props)
+        if p.morphism is None:
+            return  [copy.copy(p) for i in range(n)] 
+        else:
+            return self._split_multiple(p)
+
+    def _topology(self,raw):
+        spl = re.split(r"\s*(=>|->|\[|\])\s*", raw)
+        spl = list(filter(lambda x: x!="[" and x!="]" and x!="", spl))
+        left = spl[0].split(",")
+        right = spl[2].split(",")
+        if self.issub:
+            for i in range(len(left)):
+                left[i] = self.fact.name + str(Parser.subgr_count) + "_" + left[i]
+            for i in range(len(right)):
+                right[i] = self.fact.name + str(Parser.subgr_count) + "_" + right[i]
+        if (len(left)>1) and (len(right)>1):
+            raise Exception("ERROR: Ambigious multiple connection in line:\n\t{}".format(raw))
+        # many to one conection
+        elif len(left)>1:
+            if len(spl) < 4:
+                spl.append("")
+            morphs = self._multiple_morphs(spl[3], len(left))
+            if len(morphs)!=len(left):
+                raise Exception("\tERROR: Count of edges do not match to count of states in many to one connection!\n\t\t{}".format(raw))
+            self.fact.add_state(right[0])
+            for i, st in enumerate(left):
+                self.fact.add_state(st)
+                self.fact.add_connection(st, right[0], morphs[i].morphism)
+        # one to many connection, here could be selector
+        elif len(right)>1:
+            if len(spl) < 4:
+                spl.append("")
+            morphs = self._multiple_morphs(spl[3], len(right))
+            self.fact.add_state(left[0])
+            if len(morphs)!=len(right):
+                raise Exception("\tERROR: Count of edges do not match to count of states in one to many connection!\n\t\t{}".format(raw))
+            for i, st in enumerate(right):
+                self.fact.add_state(st)
+                self.fact.add_connection(left[0], st, morphs[i].morphism, morphs[i].order)
+        # one to one connection
+        else:
+            self.fact.add_state(left[0])
+            self.fact.add_state(right[0])
+            if len(spl)==4:
+                pr =self._param_from_props(spl[3])
+                self.fact.add_connection(left[0], right[0], pr.morphism, ordr=pr.order if pr.order is not None else 0)
+            elif len(spl)==3:
+                self.fact.add_connection(left[0], right[0], None)
+
+    def parse_file(self, filename):
+        # @todo В случае, если на вход будет подан файл в отличной от UTF-8 кодировке программа работать не будет
+        file = open(filename, encoding='utf-8')# "r")
+        dot = file.read()
+        self._check_brackets(dot)
+        
+        comments = [m for m in re.finditer(r'\".*\"', dot)]
+        for m in comments:
+            dot=dot[:m.span()[0]]+(dot[m.span()[0]:m.span()[1]]).replace(' ','\0')+dot[m.span()[1]:]
+        dot = re.sub(r"[ \t\r]", "", dot) #deleting all spaces
+        dot = re.sub(r"((digraph)|}|{)", "", dot)
+        dot = re.sub(r"\/\/.*", "", dot)
+        dot = re.sub(r"^\n$", "", dot)
+        dotlines = dot.splitlines()
+        dotlines = list(filter(None, dotlines))
+        self.fact.name = dotlines[0]
+        dotlines = dotlines[1:]
+        # ent_re - regular expr for edges, states, functions properties
+        ent_re = re.compile(r"^\w+\[.*\]$")
+        # top_re - regular expr for topology properties, most time consuming one
+        top_re = re.compile(r"^(\w+,?)+(->|=>)(\w+,?)+(\[(\w+=(\(?\w+,?\)?)+,?)+\])?")
+        # (r"^\w[\w\s,]*(->|=>)\s*\w[\w\s,=\[\]()]*$")
+        for i, ln in enumerate(dotlines):
+            if ent_re.match(ln):
+                name, parm = self._param_from_entln(ln)
+                self.fact.entities[name] = parm
+            elif top_re.match(ln):
+                self._topology(ln)
+        return self.fact.build(Parser.subgr_count)
+
+    checked=[]
+    bushes = {}
+    selectorends = {}
+    def generate_cpp(self, filename=None):
+        self.fact.graph.init_state.input_edges_number =0
+        states_to_check = [self.fact.graph.init_state]
+        while len(states_to_check)!=0:
+            for st in states_to_check:
+                self.checked.append(st)
+                states_to_check.remove(st)
+                bush = _Bush(st)
+                bush.grow_bush()
+                self.bushes[st] = bush
+                for outs in bush.outstates:
+                    if outs not in states_to_check and outs not in self.checked:
+                        states_to_check.append(outs)
+        send_token(self.fact.graph.init_state, self.bushes, [])
+        preds, morphs, sels, st, body = print_graph(self.fact.graph.init_state, self.fact.entities, self.bushes)
+        from mako.template import Template
+        if filename is not None:
+            f = open(filename, "w")
+        else:
+            f= open(self.fact.name + ".cpp", "w")
+        print(Template(filename="./cpp/template.cpp").render(preds=preds, morphs = morphs, sels = sels, states=st, body=body), file=f)
+
+def print_graph(cur_state, entities, bushes):
+    checked = []
+    toloadpred = []
+    toloadmorph = []
+    toloadsel =[]
+    tocheck = [cur_state]
+    body = ""
+    while len(tocheck) !=0:
+        cur_state=tocheck[0]
+        cur_b = bushes[cur_state]
+        cur_b.token+=1
+        if cur_b.token < cur_b.state.input_edges_number - cur_b.state.looped_edges_number:
+            tocheck.remove(cur_state)
+            tocheck.append(cur_state)
+            continue
+        if cur_state in checked:
+            tocheck.remove(cur_state)
+            continue
+        if len(cur_b.branches)>1 or len(cur_b.incomes)>1:
+            body+="{}:\n".format(cur_state.name)
+        if len(cur_b.incomes)!=0:
+            if cur_b.state.comment!="" and cur_b.state.comment is not None:
+                print("STcomm:", cur_b.state.comment)
+                body+="//"+cur_b.state.comment+"\n"
+            stri = "false "
+            for inc in cur_b.incomes:
+                stri += "|| SEL_{}[{}] ".format(inc["st"].name, inc["i"])
+            body+="if (!({}))".format(stri)
+            body+="{\n\tfor (int seli = 0;"+" seli < {};".format(len(cur_state.transfers))+" seli++)\n"+ "\t\tSEL_{}[seli]=false;".format(cur_state.name)+"\n}"
+            if cur_state.selector.name != "":
+                # print(cur_state.name, cur_state.selector)
+                if cur_state.selector not in toloadsel:
+                    toloadsel.append(cur_state.selector)
+                body+="else {\n"+ "\tSEL_{} = {}(&data);//{}\n".format(cur_state.name, cur_state.selector, cur_state.selector.comment )+"}\n"
+            else:
+                body+="else {\n\tfor (int seli = 0;"+" seli < {};".format(len(cur_state.transfers))+" seli++)\n"+"\t\tSEL_{}[seli]=true;".format(cur_state.name)+"\n}\n"
+        for i, br in enumerate(cur_b.branches):
+            body+="if (SEL_{}[{}])".format(cur_state.name, i)+"{\n"
+            if br[len(br)-1].output_state not in tocheck:
+                tocheck.append(br[len(br)-1].output_state)
+            if br[len(br)-1].output_state in checked or br[len(br)-1].output_state is cur_state:
+                stri, toloadpred, toloadmorph = cur_b.cpp_branch(i, toloadpred, toloadmorph)
+                body+=stri+"\tgoto {};\n".format(br[len(br)-1].output_state.name)+"}\n"
+            else:
+                stri, toloadpred, toloadmorph = cur_b.cpp_branch(i, toloadpred, toloadmorph) 
+                body+=stri+"}\n"
+        tocheck.remove(cur_state)
+        checked.append(cur_state)
+    return _unique(toloadpred), _unique(toloadmorph), _unique(toloadsel), checked, body
+
+def _unique(lst):
+    for i, el in enumerate(lst):
+        for el2 in lst[i+1:]:
+            if el2.module == el.module and el2.name == el.name:
+                lst.remove(el2)
+    return lst
+
+def send_token(cur_state, bushes, checked):
+    cur_b = bushes[cur_state]
+    if cur_state in checked:
+        return
+    if len(cur_b.outstates)==0:
+        return
+    if len(cur_b.incomes) == cur_b.state.input_edges_number - cur_b.state.looped_edges_number:
+        checked.append(cur_state)
+        for i,br in enumerate(cur_b.branches):
+            bushes[br[len(br)-1].output_state].incomes.append({"st":cur_state, "i":i})
+            send_token(br[len(br)-1].output_state,bushes, checked)
+
+class _Bush():
+    __slots__=(
+        'state', 
+        'selector',
+        'branches',
+        'outstates',
+        'token',
+        'incomes',
+        'selectorfin'
+    )
+
+    def __init__(self, state):
+        self.state = state
+        self.selector = state.selector
+        self.branches = []
+        self.outstates = []
+        self.token = 0
+        self.incomes = []
+
+    def grow_bush(self):
+        for t in self.state.transfers:
+            branch = [t]
+            self._gen_branch(t.output_state, branch)
+        
+    def _gen_branch(self, cur_state, branch):
+        while len(cur_state.transfers)==1 and cur_state.input_edges_number==1:
+            if cur_state._proxy_state is not None:
+                cur_state=cur_state._proxy_state
+            tr = cur_state.transfers[0]
+            branch.append(tr)
+            cur_state = tr.output_state
+        self.branches.append(branch)
+        if cur_state not in self.outstates:
+            self.outstates.append(cur_state)
+        
+    def cpp_branch(self, i, toloadpred, toloadmorph):
+        res = ""
+        for tr in self.branches[i]:
+            edge = tr.edge
+            if edge.comment!="":
+                res+="\t//{}\n".format(edge.comment)
+            if edge.pred_f.name != "":
+                if edge.pred_f not in toloadpred:
+                    toloadpred.append(edge.pred_f)
+                res+="\tcheck_pred({}(&data), \"{}\");".format(edge.pred_f, edge.pred_f)
+                res+="//{}\n".format(edge.pred_f.comment) if edge.pred_f.comment != "" else "\n"
+            if edge.morph_f.name != "":
+                if edge.morph_f not in toloadmorph:
+                    toloadmorph.append(edge.morph_f)
+                res+="\t{}(&data);".format(edge.morph_f)
+                res+="//{}\n".format(edge.morph_f.comment) if edge.morph_f.comment != "" else "\n"
+        return res, toloadpred, toloadmorph
+
+
+   
+
diff --git a/comsdk/research.py b/comsdk/research.py
index 9c1e1f1a32d529bb5a3e04238a6d1cc98ebaf30f..ca45e3d597afdf44ae1cff715c2588e3523cb663 100644
--- a/comsdk/research.py
+++ b/comsdk/research.py
@@ -2,7 +2,7 @@ import os
 import pickle
 import shutil
 from datetime import datetime, date
-from comsdk.aux import *
+from comsdk.comaux import *
 from comsdk.communication import *
 from comsdk.distributed_storage import *
 from comsdk.edge import Edge, dummy_predicate
diff --git a/comsdk/test.adot b/comsdk/test.adot
new file mode 100644
index 0000000000000000000000000000000000000000..bc95ee3f52f4157cfdf31bb911e88c64fff57db7
--- /dev/null
+++ b/comsdk/test.adot
@@ -0,0 +1,40 @@
+digraph CODEOBJECT_GENERATOR
+{
+// ??????????? ???????-????????????
+	FUNC_1 [module=case_gen_funcs, entry_func=function_1]
+	FUNC_2 [module=case_gen_funcs, entry_func=function_2]
+	FUNC_3 [module=case_gen_funcs, entry_func=function_3]
+	SAVE_TO_DB [module=case_gen_funcs, entry_func=save_to_db]
+	SAVE_TO_FILE [module=case_gen_funcs, entry_func=save_to_file]
+	REPEAT [module=case_gen_funcs, entry_func=repeat]
+	EXIT [module=case_gen_funcs, entry_func=exit]
+	CREATE_DUMP [module=case_gen_funcs, entry_func=create_dump]
+// ??????????? ???????-??????????
+	PREDICATE_X [module=predicate_funcs, entry_func=predicate_x]
+	PREDICATE_Y [module=predicate_funcs, entry_func=predicate_y]
+	SELECTOR [module=predicate_funcs, entry_func=selector]
+// ??????????? ??????? ???????? (????????)
+	EDGE_1 [predicate=PREDICATE_X, function=FUNC_1]
+	EDGE_2 [predicate=PREDICATE_Y, function=FUNC_2]
+	EDGE_3 [predicate=PREDICATE_X, function=FUNC_3]
+	EDGE_4 [predicate=PREDICATE_Y, function=SAVE_TO_DB]
+	EDGE_5 [predicate=PREDICATE_X, function=SAVE_TO_FILE]
+	EDGE_6 [predicate=PREDICATE_Y, function=REPEAT]
+	EDGE_7 [predicate=PREDICATE_X, function=EXIT]
+	EDGE_8 [function=EXIT]
+	EDGE_9 [predicate=CHECK_DUMP, function=EXIT]
+	EDGE_10 [function=CREATE_DUMP]
+// ? ???? ??????? ????????? ????????????????? 	
+	CONTENT_SUBSTITUTED [parallelism=threading]
+// ??????????? ???????? ??????
+	__BEGIN__ -> INPUT_READY
+	INPUT_READY -> TEPMLATE_COPIED [morphism=EDGE_1]
+	TEPMLATE_COPIED -> NAMES_SUBSTITUTED [morphism=EDGE_2]
+	NAMES_SUBSTITUTED -> CONTENT_SUBSTITUTED [morphism=EDGE_3]
+	CONTENT_SUBSTITUTED => DUMP_CREATED [morphism=EDGE_10]
+	CONTENT_SUBSTITUTED -> RESULT_SAVED [morphism=EDGE_4]
+	CONTENT_SUBSTITUTED -> RESULT_SAVED [morphism=EDGE_5]
+// ? ??????????? ?? ?????? ?????????? SELECTOR ?????????????? ??????? ?? ??????? ??? ??????? ?????
+	RESULT_SAVED -> INPUT_READY, __END__ [selector=SELECTOR, morphism=(EDGE_6, EDGE_7)]
+	RESULT_SAVED, DUMP_CREATED -> __END__ [morphism=(EDGE_8, EDGE_9)]
+}
\ No newline at end of file
diff --git a/cpp/printers.cpp b/cpp/printers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..52f6cd0353bcda8ea48f042ccf41287e89d351b5
--- /dev/null
+++ b/cpp/printers.cpp
@@ -0,0 +1,36 @@
+#include <iostream>
+#include <anymap.h>
+
+extern "C" {
+    int PrintHello(com::Anymap) {
+        std::cout<<"Hello!" << std::endl;
+        return 0;
+    }
+
+    int PrintBye(com::Anymap) {
+        std::cout<<"Bye!" << std::endl;
+        return 0;
+    }
+
+    int PrintA(com::Anymap) {
+        std::cout<<"A" << std::endl;
+        return 0;
+    }
+
+    int PrintB(com::Anymap) {
+        std::cout<<"B" << std::endl;
+        return 0;
+    }
+
+    bool ReturnTrue(){
+        return true;
+    }
+
+    bool ReturnFalse(){
+        return false;
+    }
+
+    std::list<bool> ThreeTrue(){
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/cpp/run.sh b/cpp/run.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f7d40f63826e8e5463530cdc240ed4dec5c50d38
--- /dev/null
+++ b/cpp/run.sh
@@ -0,0 +1,9 @@
+g++ -c -fPIC ./dev/core/anymap.cpp -o anymap.o -I./dev;
+g++ -c -fPIC  tests.cpp -o tests.o -I./dev;
+# g++ -c -fPIC ./dev/iniparser/iniparser.cpp -o iniparser.o -I./dev;
+g++ tests.o anymap.o -shared -o libtest.so; rm tests.o anymap.o;
+if g++ $1 -o graph.out -I./dev ./dev/core/anymap.cpp -ldl; then
+./graph.out;
+else 
+ echo "Not Compiled!";
+fi;
\ No newline at end of file
diff --git a/cpp/template.cpp b/cpp/template.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9aa7bba0e17baef44092c3cbd0a008521d8c7b75
--- /dev/null
+++ b/cpp/template.cpp
@@ -0,0 +1,59 @@
+#include <libtools.h>
+#include <anymap.h>
+#include <iniparser.h>
+
+typedef std::function<int(com::Anymap*)> IntFunc;
+typedef std::function<bool(com::Anymap*)> BoolFunc;
+typedef std::function<bool*(com::Anymap*)> BoolArrFunc;  
+
+IntFunc LoadEntry(std::string lib, std::string func) {
+    DllHandle handler;
+    return com::lib::loadFunction<int (com::Anymap*), DllHandle>(lib.c_str(), func.c_str(), handler);
+}
+
+BoolFunc LoadPred(std::string lib, std::string func) {
+    DllHandle handler;
+    return com::lib::loadFunction<int (com::Anymap*), DllHandle>(lib.c_str(), func.c_str(), handler);
+}
+
+BoolArrFunc LoadSelector(std::string lib, std::string func){
+    DllHandle handler;
+    return com::lib::loadFunction<bool* (com::Anymap*), DllHandle>(lib.c_str(), func.c_str(), handler);
+}
+
+void check_pred(bool predval, std::string predname) {
+    if (!predval) {
+        std::cout<<"Predicate "<<predname<<" returned FALSE!"<<std::endl;
+        exit(-1);
+    }   
+}
+
+int main(int argc, char const *argv[])
+{   
+    auto data = com::Anymap();
+    //Predicates
+% for pred in preds:
+    auto ${pred} = LoadPred("${pred.module}", "${pred.name}"); 
+% endfor
+    //Entry functions
+% for morph in morphs:
+    auto ${str(morph)} = LoadEntry("${morph.module}", "${morph.name}"); 
+% endfor
+    //Selectors
+% for sel in sels:
+    auto ${str(sel)} = LoadSelector("${sel.module}", "${sel.name}"); 
+% endfor
+    //Branch tokens
+    bool* SEL_${states[0].name} = new bool[${len(states[0].transfers)}];
+    std::fill_n(SEL_${states[0].name}, ${len(states[0].transfers)}, true);
+% for st in states[1:]:
+    bool* SEL_${st.name} = new bool[${len(st.transfers)}];
+    std::fill_n(SEL_${st.name}, ${len(st.transfers)}, false);
+% endfor
+
+${body}
+
+TERM:
+    std::cout<<"Termination!\n"; 
+    return 0;
+}
\ No newline at end of file
diff --git a/test_funcs/__init__.py b/test_funcs/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/test_funcs/__pycache__/__init__.cpython-37.pyc b/test_funcs/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8300123196cdd46044f029b6d36d2d032e00c2d0
Binary files /dev/null and b/test_funcs/__pycache__/__init__.cpython-37.pyc differ
diff --git a/test_funcs/__pycache__/simplest.cpython-37.pyc b/test_funcs/__pycache__/simplest.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9325caa8e4bb079839e61965e3f86352010caf45
Binary files /dev/null and b/test_funcs/__pycache__/simplest.cpython-37.pyc differ
diff --git a/test_funcs/simplest.py b/test_funcs/simplest.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d357c28fa3f6c2f0641985e35cc082534a4e71e
--- /dev/null
+++ b/test_funcs/simplest.py
@@ -0,0 +1,34 @@
+def dummy_edge(data):
+    pass
+
+def increment_a_edge(data):
+    data['a'] += 1
+
+def increment_a_array_edge(data):
+    for i in range(len(data['a'])):
+        data['a'][i] += 1
+
+def increment_b_edge(data):
+    data['b'] += 1
+
+def decrement_a_edge(data):
+    data['a'] -= 1
+
+def nonzero_predicate(data):
+    return data['a'] != 0 
+
+def positiveness_predicate(data):
+    return data['a'] > 0 
+
+def nonpositiveness_predicate(data):
+    return data['a'] <= 0 
+
+def copy_to_c(data):
+    data['c'] = data['a']
+
+def selector_a_nonpositive(data):
+    res = data['a'] <= 0
+    return [res, not res]
+
+def true_predicate(data):
+    return True
diff --git a/tests/__pycache__/test_graph.cpython-37.pyc b/tests/__pycache__/test_graph.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..210eeb9df598a9e610767e642839d77107d9e0cf
Binary files /dev/null and b/tests/__pycache__/test_graph.cpython-37.pyc differ
diff --git a/tests/__pycache__/test_parser.cpython-37.pyc b/tests/__pycache__/test_parser.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6507451d786bb069e2d5db775d48ded878be3a21
Binary files /dev/null and b/tests/__pycache__/test_parser.cpython-37.pyc differ
diff --git a/tests/adot/add.adot b/tests/adot/add.adot
new file mode 100644
index 0000000000000000000000000000000000000000..e12c29ededc85084b136af109d2796fe67211c07
--- /dev/null
+++ b/tests/adot/add.adot
@@ -0,0 +1,8 @@
+digraph ADD {
+    FUNC [module=test_funcs.simplest, entry_func=increment_b_edge]
+    PRED [module=test_funcs.simplest, entry_func=positiveness_predicate]
+    MORPH [predicate=PRED, function=FUNC, comment="ADD"]
+    
+    __BEGIN__ ->  ST [morphism = MORPH]
+    ST -> __END__ 
+}
\ No newline at end of file
diff --git a/tests/adot/branching.adot b/tests/adot/branching.adot
new file mode 100644
index 0000000000000000000000000000000000000000..e8c14dea2182d4a8629053871a326872f4fddb07
--- /dev/null
+++ b/tests/adot/branching.adot
@@ -0,0 +1,15 @@
+digraph SIMPLEST {
+    FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge]
+    FUNCB [module=test_funcs.simplest, entry_func=increment_b_edge]
+    PRED [module=test_funcs.simplest, entry_func=true_predicate]
+    
+    INCR_A [predicate=PRED, function=FUNCA]
+    INCR_B [predicate=PRED, function=FUNCB]
+    
+    __BEGIN__ -> ROOT
+    ROOT ->  BR1, BR2 [morphism=(INCR_A, INCR_B)]
+    BR1 -> BR1_ST [morphism=INCR_A]
+    BR2 -> BR2_ST [morphism=INCR_B]
+    BR1_ST, BR2_ST -> MERGE [morphism=(INCR_A, INCR_B)]
+    MERGE -> __END__
+} 
\ No newline at end of file
diff --git a/tests/adot/complex.adot b/tests/adot/complex.adot
new file mode 100644
index 0000000000000000000000000000000000000000..3ea224c98daaee0aa0069957b4af5e4b07a8ed76
--- /dev/null
+++ b/tests/adot/complex.adot
@@ -0,0 +1,15 @@
+digraph SIMPLEST {
+    FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge]
+    PRED [module=test_funcs.simplest, entry_func=true_predicate]
+    
+    INCR_A [predicate=PRED, function=FUNCA]
+    
+    ST1 [subgraph=tests/adot/trivial.adot]
+    ST2 [subgraph=tests/adot/cycled.adot]
+    ST3 [subgraph=tests/adot/branching.adot]
+
+    __BEGIN__ -> ST1 
+    ST1 -> ST2 [morphism=INCR_A]
+    ST2 -> ST3 [morphism=INCR_A]
+    ST3 -> __END__ 
+} 
\ No newline at end of file
diff --git a/tests/adot/cppbranching.adot b/tests/adot/cppbranching.adot
new file mode 100644
index 0000000000000000000000000000000000000000..3b5a0a549585628c591168103da43e93cb0c7772
--- /dev/null
+++ b/tests/adot/cppbranching.adot
@@ -0,0 +1,28 @@
+digraph SIMPLEST {
+    FUNCA [module=libtest, entry_func=IncA]
+    FUNCB [module=libtest, entry_func=IncB]
+    
+    CHECKA [module=libtest, entry_func=CheckAEq4]
+    CHECKB [module=libtest, entry_func=CheckBEq4]
+    
+    SETA [module=libtest, entry_func=SetAEq1]
+    SETB [module=libtest, entry_func=SetBEq1]
+
+    PASS [module=libtest, entry_func=PassFunc]
+    PRED [module=libtest, entry_func=PassPred]
+
+    INCR_A [predicate=PRED, function=FUNCA]
+    INCR_B [predicate=PRED, function=FUNCB]
+    CH_A [predicate=CHECKA, function = PASS]
+    SET_A [predicate=PRED, function=SETA]
+    SET_B [predicate=PRED, function=SETB]
+    CH_B [predicate=CHECKB, function = PASS]
+    
+    __BEGIN__ -> ROT [morphism=SET_A]
+    ROT -> ROOT[morphism=SET_B]
+    ROOT ->  BR1, BR2 [morphism=(INCR_A, INCR_B)]
+    BR1 -> BR1_ST [morphism=INCR_A]
+    BR2 -> BR2_ST [morphism=INCR_B]
+    BR1_ST, BR2_ST -> MERGE [morphism=(INCR_A, INCR_B)]
+    MERGE -> __END__, __END__ [morphism=(CH_A, CH_B)]
+} 
\ No newline at end of file
diff --git a/tests/adot/cppcomplex.adot b/tests/adot/cppcomplex.adot
new file mode 100644
index 0000000000000000000000000000000000000000..c93c09ec2a9aacd7abde6c5f23a2072437f16839
--- /dev/null
+++ b/tests/adot/cppcomplex.adot
@@ -0,0 +1,15 @@
+digraph SIMPLEST {
+    FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge]
+    PRED [module=test_funcs.simplest, entry_func=true_predicate]
+    
+    INCR_A [predicate=PRED, function=FUNCA]
+    
+    ST1 [subgraph=tests/adot/cpptrivial.adot]
+    ST2 [subgraph=tests/adot/cppcycled.adot]
+    ST3 [subgraph=tests/adot/cppbranching.adot]
+
+    __BEGIN__ -> ST1 
+    ST1 -> ST2 
+    ST2 -> ST3 
+    ST3 -> __END__ 
+} 
\ No newline at end of file
diff --git a/tests/adot/cppcycled.adot b/tests/adot/cppcycled.adot
new file mode 100644
index 0000000000000000000000000000000000000000..ed3209bc780cf9eaa2b7ffef94c5bbde7ab83120
--- /dev/null
+++ b/tests/adot/cppcycled.adot
@@ -0,0 +1,18 @@
+digraph CYCLED {
+
+    SETA [module=libtest, entry_func=SetAEq10]
+    FUNC [module=libtest, entry_func=DecA]
+    PRED [module=libtest, entry_func=PassPred]
+
+    SET [predicate=PRED, function=SETA]
+    MORPH [predicate=PRED, function=FUNC]
+
+    SEL [module = libtest, entry_func=SelectorA]
+
+    ST2 [selector = SEL]
+    
+    __BEGIN__ -> ST1 [morphism=SET]
+    ST1 -> ST2 [morphism=MORPH]
+    ST2 -> ST1 [order=1]
+    ST2 -> __END__ [order = 2]
+}
\ No newline at end of file
diff --git a/tests/adot/cpptrivial.adot b/tests/adot/cpptrivial.adot
new file mode 100644
index 0000000000000000000000000000000000000000..c37cb9c1fe8393522e05dc62288d8b052f7424b0
--- /dev/null
+++ b/tests/adot/cpptrivial.adot
@@ -0,0 +1,9 @@
+digraph SIMPLE {
+    FUNC [module=libtest, entry_func=IncA]
+    PRED [module=libtest, entry_func=PassPred]
+    MORPH [predicate=PRED, function=FUNC]
+
+        __BEGIN__ -> ST1 [morphism = MORPH]
+    ST1 -> ST2 [morphism = MORPH]
+    ST2 -> __END__ [morphism = MORPH]
+}
\ No newline at end of file
diff --git a/tests/adot/cycled.adot b/tests/adot/cycled.adot
new file mode 100644
index 0000000000000000000000000000000000000000..4b37cbcb3a5306edae2c41a651252f0e05627d4d
--- /dev/null
+++ b/tests/adot/cycled.adot
@@ -0,0 +1,14 @@
+digraph CYCLED {
+    FUNC [module=test_funcs.simplest, entry_func=decrement_a_edge]
+    PRED [module=test_funcs.simplest, entry_func=true_predicate]
+    MORPH [predicate=PRED, function=FUNC]
+
+    SEL [module = test_funcs.simplest, entry_func = selector_a_nonpositive]
+
+    ST2 [selector = SEL]
+    
+    __BEGIN__ -> ST1 
+    ST1 -> ST2 [morphism=MORPH]
+    ST2 -> ST1 [order=2]
+    ST2 -> __END__ [order = 1]
+}
\ No newline at end of file
diff --git a/tests/adot/file.adot b/tests/adot/file.adot
new file mode 100644
index 0000000000000000000000000000000000000000..6076637bf3e355453552ce2e62238b6c39ce1bed
--- /dev/null
+++ b/tests/adot/file.adot
@@ -0,0 +1,54 @@
+digraph gcdhom_inverted_model_pso
+{
+// Определение функций-обработчиков
+	PASS_PROCESSOR [module=libcomsdk, entry_func=pass_processor]
+	CHECK_PSO_AGENT_REINIT [module=libgcdfes, entry_func=check_pso_agent_reinit, comment="Проверка о необходимости реинициализации отдельной частицы (смещение частицы) в рое в рамках метода роя частиц."]
+	CHECK_PSO_SWARM_REINIT [module=libgcdfes, entry_func=check_pso_swarm_reinit, comment="Проверка о необходимости реинициализации всего роя частиц в рамках метода роя частиц."]
+
+	PSO_AGENT_REINIT [module=libgcdfes, entry_func=pso_agent_reinit, comment="Реинициализация отдельной частицы (смещение частицы) в рое в рамках метода роя частиц."]
+	PSO_SWARM_REINIT [module=libgcdfes, entry_func=pso_swarm_reinit, comment="Реинициализация всего роя частиц в рамках метода роя частиц."]
+	
+	PSO_SWARM_ANALYSING [module=libgcdfes, entry_func=pso_swarm_analysing, comment="Анализ всего роя частиц в рамках метода роя частиц."]
+	
+	PSO_HOM_AGENT_POSTPROC [module=libgcdfes, entry_func=pso_hom_agent_postproc, comment="Постпроцессинг после решения отдельной задачи методом асимптотического осреднения."]
+	
+	PSO_TASK_DATA_REINIT [module=libgcdfes, entry_func=pso_task_data_reinit, comment="Реинициализация постановки задачи анализа эффективных характеристик КМ методом асимптотического осреднения."]
+	
+	PSO_AGENT_INIT [module=libgcdfes, entry_func=pso_agent_init, comment="Инициализация отдельной частицы в рамках метода роя частиц."]
+
+	PSO_SWARM_INIT [module=libgcdfes, entry_func=pso_swarm_init, comment="Инициализация роя частиц."]
+	
+	PSO_INIT [module=libgcdfes, entry_func=pso_swarm_init, comment="Инициализация метода роя частиц."]
+
+// Определение функций-предикатов
+	PASS_PREDICATE [module=libcomsdk, entry_func=pass_predicate]
+	
+// Определение морфизмов
+	PASS_MORPHISM [predicate=PASS_PREDICATE, function=PASS_PROCESSOR, comment="ПАСС, морфизм."]
+	
+	PSO_AGENT_REINIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_AGENT_REINIT]
+	PSO_SWARM_REINIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_SWARM_REINIT]
+	PSO_SWARM_ANALYSING_MORPHISM [predicate=PASS_PREDICATE, function=PSO_SWARM_ANALYSING]
+	PSO_HOM_AGENT_POSTPROC_MORPHISM [predicate=PASS_PREDICATE, function=PSO_HOM_AGENT_POSTPROC] 
+	PSO_TASK_DATA_REINIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_TASK_DATA_REINIT] 
+	PSO_AGENT_INIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_AGENT_INIT] 
+	PSO_SWARM_INIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_SWARM_INIT] 
+	PSO_INIT_MORPHISM [predicate=PASS_PREDICATE, function=PSO_INIT] 
+	
+// Определение атрибутов узлов	
+	S_1 [subgraph=gcdhom_preprocessor.adot]
+	S_5 [subgraph=gcdhom_processor.adot]
+	S_6 [selector=CHECK_PSO_AGENT_REINIT]
+	S_7 [selector=CHECK_PSO_SWARM_REINIT]
+
+// Определение топологии графовой модели метода конечных элементов
+	__BEGIN__ -> S_1
+	S_1 -> S_2 [morphism=PSO_INIT_MORPHISM]
+	S_2 -> S_3 [morphism=PSO_SWARM_INIT_MORPHISM]
+	S_3 -> S_4 [morphism=PSO_AGENT_INIT_MORPHISM]
+	S_4 -> S_5 [morphism=PSO_TASK_DATA_REINIT_MORPHISM]
+	S_5 -> S_6 [morphism=PSO_HOM_AGENT_POSTPROC_MORPHISM]
+	S_6 -> S_4, S_7 [morphism=(PSO_AGENT_REINIT_MORPHISM, PSO_SWARM_ANALYSING_MORPHISM), order=(10,20)]
+	S_7 -> S_4, S_8 [morphism=(PSO_SWARM_REINIT_MORPHISM, PASS_MORPHISM), order=(30,40)]
+	S_8 -> __END__ [comment = "Расчет завершён."]
+}
diff --git a/tests/adot/testparal.adot b/tests/adot/testparal.adot
new file mode 100644
index 0000000000000000000000000000000000000000..4f275f0e79fceeac99b50037343e96bd51a17088
--- /dev/null
+++ b/tests/adot/testparal.adot
@@ -0,0 +1,17 @@
+digraph SIMPLEST {
+    FUNCA [module=test_funcs.simplest, entry_func=increment_a_edge]
+    FUNCB [module=test_funcs.simplest, entry_func=increment_b_edge]
+    PRED [module=test_funcs.simplest, entry_func=positiveness_predicate]
+    INCR_A [predicate=PRED, function=FUNCA]
+    INCR_B [predicate=PRED, function=FUNCB]
+    
+
+    __BEGIN__ -> ROOT
+    ROOT ->  BR1, BR2, BR3 [morphism=(INCR_A, INCR_A, INCR_A)]
+    //BR3 -> SIBL3_BR1, SIBL3_BR2 [morphism=(INCR_A, INCR_A)]
+    //BR2 -> SIBL2_BR1, SIBL2_BR2 [morphism=(INCR_A, INCR_A)]
+    //SIBL3_BR1 -> SIBL3_BR1_1,  SIBL3_BR1_2 [morphism=(INCR_A, INCR_A)]
+    //SIBL3_BR1_1,  SIBL3_BR1_2 -> TERM  [morphism=(INCR_A, INCR_A)]
+    //BR1,  SIBL2_BR1, SIBL2_BR2, TERM, SIBL3_BR2 ->  __END__ [morphism=(INCR_A, INCR_A, INCR_A, INCR_A, INCR_A)]
+    BR1, BR2, BR3 -> __END__ [morphism=(INCR_A, INCR_A, INCR_A)]
+} 
\ No newline at end of file
diff --git a/tests/adot/testsub.adot b/tests/adot/testsub.adot
new file mode 100644
index 0000000000000000000000000000000000000000..42391b8e86484ace7e8d443394991f28b626bae1
--- /dev/null
+++ b/tests/adot/testsub.adot
@@ -0,0 +1,14 @@
+digraph TEST_SUB {
+    FUNC [module=test_funcs.simplest, entry_func=increment_a_edge]
+    PRED [module=test_funcs.simplest, entry_func=positiveness_predicate]
+    MORPH [predicate=PRED, function=FUNC]
+    SEL [module=test_funcs.simplest, entry_func=selector_a_nonpositive]
+    
+    ST2 [subgraph = tests/adot/file.adot]
+    ST3 [selector = SEL]
+
+    __BEGIN__ -> ST1 [morphism = MORPH]
+    ST1 -> ST2 
+    ST2 -> ST3 
+    ST3 -> __END__ 
+}
\ No newline at end of file
diff --git a/tests/adot/trivial.adot b/tests/adot/trivial.adot
new file mode 100644
index 0000000000000000000000000000000000000000..26a06b741eefec6c26dc5d8a6ec048c4d384f324
--- /dev/null
+++ b/tests/adot/trivial.adot
@@ -0,0 +1,9 @@
+digraph TRIVIAL {
+    FUNC [module=test_funcs.simplest, entry_func=increment_a_edge]
+    PRED [module=test_funcs.simplest, entry_func=true_predicate]
+    MORPH [predicate=PRED, function=FUNC, comment="ADD"]
+
+    __BEGIN__ -> ST1 [morphism = MORPH]
+    ST1 -> ST2 [morphism = MORPH]
+    ST2 -> __END__ [morphism = MORPH]
+}
\ No newline at end of file
diff --git a/tests/square/square b/tests/square/square
new file mode 100755
index 0000000000000000000000000000000000000000..ad02987631f2c4cdb69d2b659e8a2cc39cfd5cb8
Binary files /dev/null and b/tests/square/square differ
diff --git a/tests/test_graph.py b/tests/test_graph.py
index ab2a5df23f6d94050b8d4318f8fc202afb4e5a6f..160e2348a891f64149e5c13fd9c381e432c2c209 100644
--- a/tests/test_graph.py
+++ b/tests/test_graph.py
@@ -230,24 +230,30 @@ class GraphGoodCheck(unittest.TestCase):
 
     def _get_trivial_parallel_graph(self, initial_conditions):
         '''
-        s_1 -> s_2 -> s_3 -> s_6
-            -> s_4 -> s_5 ->
+        s_1 -> s_2 -> s_3 ---------> s6s
+            -> s_4 -> s_4_1 -> s_5 
+                   -> s_4_2            
         p_12 = p_24 = p_13 = p_34 := a not 0
         f_12 = f_24 := a + 1
         f_13 = f_34 := b + 1
         '''
 
-        s_1 = State('nonparallel_s_1', selection_policy=AllSelectionPolicy())
+        s_1 = State('nonparallel_s_1')
         s_2 = State('parallel_s_2')
         s_3 = State('parallel_s_3')
         s_4 = State('parallel_s_4')
+        s_4_1 = State('parallel_s_4_1')
+        s_4_2 = State('parallel_s_4_2')
         s_5 = State('parallel_s_5')
         s_6 = State('nonparallel_s_6')
         s_1.connect_to(s_2, edge=Edge(nonzero_predicate, increment_a_edge))
         s_2.connect_to(s_3, edge=Edge(nonzero_predicate, increment_a_edge))
         s_3.connect_to(s_6, edge=Edge(nonzero_predicate, increment_a_edge))
         s_1.connect_to(s_4, edge=Edge(nonzero_predicate, increment_b_edge))
-        s_4.connect_to(s_5, edge=Edge(nonzero_predicate, increment_b_edge))
+        s_4.connect_to(s_4_1, edge=Edge(nonzero_predicate, increment_b_edge))
+        s_4.connect_to(s_4_2, edge=Edge(nonzero_predicate, increment_b_edge))
+        s_4_1.connect_to(s_5,  edge=Edge(nonzero_predicate, increment_b_edge))
+        s_4_2.connect_to(s_6,  edge=Edge(nonzero_predicate, increment_b_edge))
         s_5.connect_to(s_6, edge=Edge(nonzero_predicate, increment_b_edge))
         correct_outputs = []
         for ic in initial_conditions:
@@ -433,15 +439,17 @@ class GraphGoodCheck(unittest.TestCase):
         p_12 = p_23 := dummy
         f_12 := a + 1
         '''
-
+        
+        pred = Func(func=dummy_predicate)
+        morph = Func(func=increment_a_edge)
         s_1 = State('s_1')
         s_2 = State('s_2')
         s_3 = State('s_3')
-        s_1.connect_to(s_2, edge=Edge(dummy_predicate, increment_a_edge))
-        s_2.connect_to(s_3, edge=Edge(dummy_predicate, increment_a_edge))
+        s_1.connect_to(s_2, edge=Edge(pred, morph))
+        s_2.connect_to(s_3, edge=Edge(pred, morph))
         sub_s_1 = State('sub_s_1')
         sub_s_2 = State('sub_s_2')
-        sub_s_1.connect_to(sub_s_2, edge=Edge(dummy_predicate, increment_a_edge))
+        sub_s_1.connect_to(sub_s_2, edge=Edge(pred, morph))
         s_2.replace_with_graph(Graph(sub_s_1, sub_s_2))
         correct_outputs = []
         for ic in initial_conditions:
diff --git a/tests/test_parser.py b/tests/test_parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..cadf7ad55faa1d80d09f1362660772746ec308f8
--- /dev/null
+++ b/tests/test_parser.py
@@ -0,0 +1,72 @@
+import unittest
+import subprocess
+
+from comsdk.graph import *
+from comsdk.parser import Parser
+
+path_to_comsdk = "/home/lbstr/bmstu/comsdk"
+path_to_pycomsdk = "/home/lbstr/bmstu/pycomsdk"
+
+class ParserGoodCheck(unittest.TestCase):
+
+    def test_trivial_graph(self):
+        parsr = Parser()
+        gr = parsr.parse_file("./tests/adot/trivial.adot")
+        data = {"a": 1}
+        gr.run(data)
+        self.assertEqual(data["a"], 4)
+
+    def test_branching_graph(self):
+        parsr = Parser()
+        gr = parsr.parse_file("./tests/adot/branching.adot")
+        data = {"a": 1, "b": 1}
+        gr.run(data)
+        self.assertEqual(data["a"], 4)
+        self.assertEqual(data["b"], 4)
+
+    def test_cycled_graph(self):
+        parsr = Parser()
+        gr = parsr.parse_file("./tests/adot/cycled.adot")
+        data = {"a": 10}
+        gr.run(data)
+        self.assertEqual(data["a"], 0)
+
+    def test_complex_graph(self):
+        parsr = Parser()
+        gr = parsr.parse_file("./tests/adot/complex.adot")
+        data = {"a": 1, "b": 1}
+        gr.run(data)
+        self.assertEqual(data["a"], 4)
+        self.assertEqual(data["b"], 4)
+
+    def test_cpp_trivial_graph(self):
+        parsr = Parser(tocpp=True)
+        gr = parsr.parse_file("./tests/adot/cpptrivial.adot")
+        parsr.generate_cpp(path_to_comsdk+"res.cpp")
+        command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp"
+        subprocess.check_output(["bash", "-c", command])
+    
+    def test_cpp_branching_graph(self):
+        parsr = Parser(tocpp=True)
+        gr = parsr.parse_file("./tests/adot/cppbranching.adot")
+        parsr.generate_cpp(path_to_comsdk+"res.cpp")
+        command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp"
+        subprocess.check_output(["bash", "-c", command])
+
+    def test_cpp_cycled_graph(self):
+        parsr = Parser(tocpp=True)
+        gr = parsr.parse_file("./tests/adot/cppcycled.adot")
+        parsr.generate_cpp(path_to_comsdk+"res.cpp")
+        command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp"
+        subprocess.check_output(["bash", "-c", command])
+
+    def test_cpp_complex_graph(self):
+        parsr = Parser(tocpp=True)
+        gr = parsr.parse_file("./tests/adot/cppcomplex.adot")
+        parsr.generate_cpp(path_to_comsdk+"res.cpp")
+        command = "cd "+path_to_comsdk+"; "+path_to_pycomsdk+"/cpp/run.sh "+path_to_comsdk+"res.cpp"
+        subprocess.check_output(["bash", "-c", command])
+
+if __name__ == '__main__':
+    unittest.main()
+