1from pyparsing import *
2import TestScripts.Parser as p
3import pickle
4
5def loadRoot(f):
6    root = None
7    with open(f,"rb") as inf:
8         root=pickle.load(inf)
9    return(root)
10
11class Params:
12    def __init__(self):
13        self.full = []
14        self.summary=None
15        self.paramNames = None
16        self.formula=""
17
18    def __str__(self):
19        return(str(self.full) + str(self.summary) + str(self.paramNames))
20
21def disabled(a):
22  return((CaselessKeyword("disabled") + "{" + a + "}") ^ a)
23
24def parsedNodeDesc( str, loc, toks ):
25    d={}
26    if "class" in toks:
27       d["class"]=toks["class"]
28    if "folder" in toks:
29       d["folder"]=toks["folder"]
30    return(d)
31
32def parseNodeSuite( str, loc, toks):
33    d={}
34    t = p.TreeElem(0)
35    if "message" in toks:
36       d["message"]=toks["message"]
37    if "class" in toks["desc"]:
38        d["class"] = toks["desc"]["class"]
39    if "folder" in toks["desc"]:
40        t.setPath(toks["desc"]["folder"])
41    d["deprecated"] = False
42    if(toks[0]=="disabled"):
43        d["deprecated"] = True
44
45    if "PARAMID" in toks:
46        d["PARAMID"] = toks["PARAMID"]
47
48    t.writeData(d)
49
50    if "params" in toks:
51        t.params=toks["params"]
52
53    for c in toks["allTests"]:
54        t.addGroup(c)
55    if "allPatterns" in toks:
56       for c in toks["allPatterns"]:
57           t.addPattern(c["ID"],c["path"])
58
59    if "allParams" in toks:
60       for c in toks["allParams"]:
61           if "path" in c:
62              t.addParam(p.TreeElem.PARAMFILE,c["ID"],c["path"])
63           if "numberList" in c:
64              #print(c["numberList"])
65              t.addParam(p.TreeElem.PARAMGEN,c["ID"],c["numberList"])
66
67    if "allOutputs" in toks:
68       for c in toks["allOutputs"]:
69           t.addOutput(c["ID"],c["path"])
70    return(t)
71
72def parseNodeGroup( str, loc, toks):
73    d={}
74    t = p.TreeElem(0)
75    if "message" in toks:
76       d["message"]=toks["message"]
77    if "class" in toks["desc"]:
78        d["class"] = toks["desc"]["class"]
79    if "folder" in toks["desc"]:
80        t.setPath(toks["desc"]["folder"])
81    d["deprecated"] = False
82    if(toks[0]=="disabled"):
83        d["deprecated"] = True
84
85    t.writeData(d)
86
87    #print(t.data["message"])
88    for c in toks["contained"]:
89        #print("  ",c.data["message"])
90        t.addGroup(c)
91    return(t)
92
93def parseTest( str, loc, toks):
94    d={}
95    if "message" in toks:
96       d["message"]=toks["message"]
97    if "class" in toks:
98        d["class"] = toks["class"]
99    d["deprecated"] = False
100    if(toks[0]=="disabled"):
101        d["deprecated"] = True
102    if "PARAMID" in toks:
103        d["PARAMID"] = toks["PARAMID"]
104    if "testData" in toks:
105        d["testData"]=toks["testData"]
106    t = p.TreeElem(0)
107    t.writeData(d)
108    return(t)
109
110def getInteger( str, loc, toks):
111    return(int(toks[0]))
112
113def parseFile( str, loc, toks):
114    d={}
115    d["ID"] = toks["ID"]
116    d["path"] = toks["path"]
117    return(d)
118
119def parseParamDesc( str, loc, toks):
120    d={}
121    d["ID"] = toks["ID"]
122    if "path" in toks:
123       d["path"] = toks["path"]
124    if "numberList" in toks:
125       d["numberList"] = toks["numberList"]
126    return(d)
127
128def parseParams( str, loc, toks):
129    p = Params()
130    p.full = toks["full"]
131    if "summary" in toks:
132        p.summary=toks["summary"]
133    if "names" in toks:
134        p.paramNames=[x.strip("\"") for x in toks["names"]]
135    if "formula" in toks:
136        p.formula=toks["formula"].strip("\"")
137    return(p)
138
139def generatorDesc( str, loc, toks):
140    d={}
141    r = list(toks["ints"])
142    d["NAME"] = toks["PARAM"]
143    d["INTS"] = r
144    return(d)
145
146def parseTestFields( str, loc, toks):
147    if "fields" in toks:
148        fields = toks["fields"]
149        # merge list of dictionnaries into a dictionnary
150        newFields = dict((key,d[key]) for d in fields for key in d)
151        return(newFields)
152
153def parseField( str, loc, toks):
154    if toks[0] == "oldID":
155       return({"oldID" : int(toks[2])})
156    if toks[0] == "truc":
157       return({"truc" : int(toks[2])})
158
159class Parser:
160    def __init__(self):
161        self.id = 0
162
163    def parse(self, filePath):
164        string = Word(alphanums+"_ =+()")
165        ident = Word( alphas+"_", alphanums+"_" )
166
167        path = Word(alphanums+"_/.")
168
169        folder = CaselessKeyword("folder") + "=" + path("folder")
170
171        nodeDesc = CaselessKeyword("class") + "=" + ident("class") + Optional(folder)
172        nodeDesc = nodeDesc.setParseAction(parsedNodeDesc)
173
174        patterns = (Keyword("Pattern")  + ident("ID") + ":" + path("path")).setParseAction(parseFile)
175        output = (Keyword("Output") + ident("ID") + ":" + path("path")).setParseAction(parseFile)
176
177        integer =  Combine( Optional(Word("+-")) + Word(nums) ).setParseAction(getInteger)
178        numberList = (ident("PARAM") + Literal("=") + "[" + delimitedList(integer,",")("ints") + "]").setParseAction(generatorDesc)
179        generator = Literal("=") + "{" + OneOrMore(numberList)("numberList") + "}"
180        fileOrGenerator = (":" + path("path")) | generator
181        params = (Keyword("Params")  + ident("ID") + fileOrGenerator).setParseAction(parseParamDesc)
182
183        paramValue = Literal("->") + ident("PARAMID")
184
185        messFormat = Word(alphanums + " _/")
186        message = messFormat("message")
187
188        testField = ((Keyword("oldID") + "=" + integer("INT")) | (Keyword("truc") + "=" + integer("INT"))).setParseAction(parseField)
189        testData = (Literal("{") + OneOrMore(testField)("fields") + Literal("}")).setParseAction(parseTestFields)
190        test = disabled((string("message") + ":" + ident("class") + Optional(testData("testData")) +  Optional(paramValue))).setParseAction(parseTest)
191
192        # paramDescription =
193        # File or
194        # List of int or
195        # Cartesian products of list
196        # Can be applied to global pattern
197        # or on a per test basis
198        paramDescription = ""
199
200        full = delimitedList(ident,",")
201        formula = Keyword("Formula") + dblQuotedString("formula")
202        paramNames = Keyword("Names") + delimitedList(dblQuotedString,",")("names")
203        summary = Keyword("Summary") + delimitedList(ident,",")("summary")
204
205        paramDetails = full("full") + Optional(summary) + Optional(paramNames)+ Optional(formula)
206
207        paramDesc=Keyword("ParamList") + Literal("{")  + paramDetails + Literal("}")
208
209        allTests = Keyword("Functions") + "{" + OneOrMore(test)("allTests") + "}" + Optional(paramValue)
210
211        allPatterns =  ZeroOrMore(patterns)
212        allOutputs =  ZeroOrMore(output)
213        allParams = ZeroOrMore(params)
214        paramList = Optional(paramDesc("params").setParseAction(parseParams))
215
216        suiteDesc = paramList + allPatterns("allPatterns") + allOutputs("allOutputs") + allParams("allParams") + allTests
217
218        suite = disabled(CaselessKeyword("suite") + message + Literal("{") + nodeDesc("desc") + suiteDesc + Literal("}"))
219        suite = suite.setParseAction(parseNodeSuite)
220
221
222        group = Forward()
223        contained = OneOrMore(group | suite)
224
225
226        group << disabled(CaselessKeyword("group") + message + Literal("{") + nodeDesc("desc") + contained("contained") + Literal("}"))
227        group=group.ignore(cStyleComment | ("//" + restOfLine ))
228        group = group.setParseAction(parseNodeGroup)
229
230
231        tree = group.parseFile( filePath )
232        tree[0].classify()
233        # We compute ID of all nodes.
234        tree[0].computeId()
235        tree[0].reident(0)
236        return(tree[0])
237