parser.py 11.8 KB
Newer Older
1 2 3 4
import re
import copy
import importlib as imp

5
from comsdk.graph import Graph, Func, State, Selector
6 7
from comsdk.edge import Edge

8

9 10 11 12 13 14 15 16 17 18
class Params():
    __slots__=(
        'module',
        'entry_func',
        'predicate',
        'selector',
        'function',
        'morphism',
        'parallelism',
        'comment',
19 20
        'order',
        'subgraph'
21 22 23 24 25 26 27 28 29 30 31
    )
    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))
        return stri

32
# entities = {}
33 34 35

class GraphFactory():
    __slots__ = (
36
        'name',
37 38
        'states', 
        'graph',
39
        'issub',
40 41 42 43 44
        'tocpp',
        'entities'
    )
    def __init__(self, tocpp=False):
        self.states = {}
45
        self.entities = {}
46
        self.tocpp = tocpp
47 48 49
        self.name = None
        self.issub = False

50
    def add_state(self, statename):
51
        if statename not in self.states:
52
            self.states[statename] = State(statename)
Savva Golubitsky's avatar
Savva Golubitsky committed
53 54
            if statename in self.entities:
                self.states[statename].comment = self.entities[statename].comment
55 56 57 58
    
    def _create_morphism(self, morphname=None):
        if morphname is None:
            return Func(), Func()
59
        pred_f, func_f = Func(), Func() 
60
        morph = self.entities[morphname]
61
        # print(morph)
62 63 64
        for m in morph.__slots__:
            if getattr(morph,m) != None:
                if m!="predicate" and m!="function":
65
                    raise Exception("ERROR: Morphisms could not have any params exept predicate and function!\n{}".format(morphname))
66
                if m=="predicate":
67 68 69
                    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)]
70 71 72 73 74
                    if self.tocpp:
                        pred_f = Func(pred.module, pred.entry_func, dummy=True)
                    else:
                        pred_f = Func(pred.module, pred.entry_func)
                if m=="function":
75 76 77
                    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)]
78 79 80 81 82 83 84
                    if self.tocpp:
                        func_f = Func(fu.module, fu.entry_func, dummy=True)
                    else:
                        func_f = Func(fu.module, fu.entry_func)
        return pred_f, func_f


85
    def add_connection(self, st1, st2, morphism=None, ordr=0):
86
        pred, entr = self._create_morphism(morphism)
87
        self.states[st1].connect_to(self.states[st2], edge=Edge(pred, entr, order=ordr))
88
        print("{} -> {}".format(st1, st2))
89

90
    def build(self, nsub):
91 92 93 94
        print("BUILDING {}\nStates:".format(self.name))
        for s in self.states:
            print("\t"+ s)
        if self.issub:
95
            self.graph = Graph(self.states[self.name+str(nsub)+"_"+"__BEGIN__"], self.states[self.name+str(nsub)+"_"+"__END__"])
96 97 98
        else:    
            self.graph = Graph(self.states["__BEGIN__"], self.states["__END__"])
        self.graph.init_graph()
99
        for s in self.states:
100
            if s in self.entities and self.entities[s].selector is not None:
101
                selname = self.entities[s].selector
102
                if self.tocpp:
103 104 105
                    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)
106 107
            else:
                self.states[s].selector =  Selector(len(self.states[s].transfers))
108
            if s in self.entities and self.entities[s].subgraph is not None:
109 110 111
                print("Replacing state {} with subgraph {}".format(s,self.entities[s].subgraph))
                parsr = Parser(subgraph=True)
                subgr = parsr.parse_file(self.entities[s].subgraph)
112
                self.states[s].replace_with_graph(subgr)
113 114
        return self.graph

Savva Golubitsky's avatar
Savva Golubitsky committed
115

116 117
class Parser():
    __slots__ = (
118 119
        'fact',
        'issub'
120
    )
121
    subgr_count = 0
122
    def __init__(self, tocpp=False, subgraph=False):
123
        self.fact = GraphFactory(tocpp=tocpp)
124 125
        self.fact.issub = subgraph
        self.issub = subgraph
126 127
        if subgraph:
            Parser.subgr_count+=1
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
    
    def _check_brackets(self, rawfile):
        br = 0
        qu = 0
        for char in rawfile:
            if char == "[":
                br+=1
            elif char == "{":
                br+=1
            elif char == "(":
                br+=1
            elif char == "]":
                br-=1
            elif char == "}":
                br-=1
            elif char == ")":
                br-=1
            elif char =="\"":
                qu+=1
        if br!=0 or qu%2!=0:
148
            raise Exception("Brackets or quotes do not match! Check your file")
149 150

    def _split_multiple(self,param):
151
        vals = {}
152 153 154
        first=True
        for s in param.__slots__:
            attr = getattr(param,s)
155
            if attr is not None and '\0' in attr:
156 157 158 159 160 161
                vals[s] = attr.split('\0')
        l=0
        for sl in vals:
            if l==0:
                l=len(vals[sl])
            elif l!=len(vals[sl]):
162
                raise Exception("\tERROR: Number of multiple params do not match", l)
163 164 165 166
        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])
167 168 169 170 171
        return res

    #Props is line "[proFp=smth, ...]"
    def _param_from_props(self,props):
        parm = Params()
172 173
        if props =="":
            return parm
174 175
        props = props.replace("]", '')
        if '(' in props:
176 177 178
            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]:]
179 180 181 182
        if '\"' in props:
            mchs = [m for m in re.finditer(r'\".*\"', props)]
            for m in mchs:
                props=props[:m.span()[0]]+(props[m.span()[0]+1:m.span()[1]-1]).replace('\0',' ')+props[m.span()[1]:]
183 184
        props = props.replace("(","")
        props = props.replace(")","")
185 186 187 188 189 190
        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:
191
                raise Exception("\tERROR:Unknown parameter: "+ r[0])
192 193 194 195 196 197
        return parm

    def _param_from_entln(self, raw):
        res = re.split(r"\[", raw, 1)
        return res[0], self._param_from_props(res[1])

198 199 200 201 202 203 204
    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)

205 206 207 208 209
    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(",")
210 211
        if self.issub:
            for i in range(len(left)):
212
                left[i] = self.fact.name + str(Parser.subgr_count) + "_" + left[i]
213
            for i in range(len(right)):
214
                right[i] = self.fact.name + str(Parser.subgr_count) + "_" + right[i]
215
        if (len(left)>1) and (len(right)>1):
216
            raise Exception("ERROR: Ambigious multiple connection in line:\n\t{}".format(raw))
217 218
        # many to one conection
        elif len(left)>1:
219 220 221
            if len(spl) < 4:
                spl.append("")
            morphs = self._multiple_morphs(spl[3], len(left))
222
            if len(morphs)!=len(left):
223
                raise Exception("\tERROR: Count of edges do not match to count of states in many to one connection!\n\t\t{}".format(raw))
224 225 226 227 228 229
            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:
230 231 232
            if len(spl) < 4:
                spl.append("")
            morphs = self._multiple_morphs(spl[3], len(right))
233
            self.fact.add_state(left[0])
234
            if len(morphs)!=len(right):
235
                raise Exception("\tERROR: Count of edges do not match to count of states in one to many connection!\n\t\t{}".format(raw))
236 237
            for i, st in enumerate(right):
                self.fact.add_state(st)
238
                self.fact.add_connection(left[0], st, morphs[i].morphism, morphs[i].order)
239 240 241 242 243 244
        # 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])
Savva Golubitsky's avatar
Savva Golubitsky committed
245
                self.fact.add_connection(left[0], right[0], pr.morphism, ordr=pr.order if pr.order is not None else 0)
246 247 248 249 250 251 252 253
            elif len(spl)==3:
                self.fact.add_connection(left[0], right[0], None)

    def parse_file(self, filename):
        file = open(filename, "r")
        dot = file.read()
        self._check_brackets(dot)
        
254 255 256
        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]:]
257
        dot = re.sub(r"[ \t\r]", "", dot) #deleting all spaces
258
        dot = re.sub(r"((digraph)|}|{)", "", dot)
259 260 261 262 263 264 265 266 267 268 269 270
        dot = re.sub(r"\/\/.*", "", dot)
        dot = re.sub(r"^\n$", "", dot)
        #print("Checking graph...")
        #graphcheck = re.search(r"\A(digraph)\w+\n?{((\/\/)*.*\n*)+}\Z", dot)
        #if graphcheck is None:
        #    print("Incorrect graph, check syntax!")
        #    exit()
        #
        #print("Graph id good, processing!")
        #dot = re.sub(r"//*$", "", dot) 
        dotlines = dot.splitlines()
        dotlines = list(filter(None, dotlines))
271 272
        self.fact.name = dotlines[0]
        dotlines = dotlines[1:]
273 274 275 276 277 278 279 280
        # 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)
281
                self.fact.entities[name] = parm
282 283
            elif top_re.match(ln):
                self._topology(ln)
284
        return self.fact.build(Parser.subgr_count)
285

Savva Golubitsky's avatar
Savva Golubitsky committed
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    toload = []
    edgemap = {}

    def _gen_branch(self,cur_state):
        root = cur_state.name
        edges = []
        while cur_state is not None:
            if len(cur_state.transfers)==0:
                cur_state = None
            elif len(cur_state.transfers)==1:
                edges.append({"pred": str(cur_state.transfers[0].edge.pred_f),
                              "morph": str(cur_state.transfers[0].edge.morph_f)})
                if str(cur_state.transfers[0].edge.pred_f) not in self.toload:
                    self.toload.append(str(cur_state.transfers[0].edge))
                if str(cur_state.transfers[0].edge.morph_f) not in self.toload:
                    self.toload.append(str(cur_state.transfers[0].edge))
                cur_state = cur_state.transfers[0].output_state
            else:
                pass
        self.edgemap[root] = list(filter(lambda x: x["morph"] != '', edges))
        return 

    def generate_cpp(self):
        self._gen_branch(self.fact.graph.init_state)
        print(self.edgemap)