Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2@file 

3@brief One class which visits a syntax tree. 

4""" 

5 

6from .translation_class import TranslateClass 

7 

8 

9class Translate2Python(TranslateClass): 

10 

11 """ 

12 Translates a code into :epkg:`Python`. 

13 """ 

14 

15 def __init__(self, code_func): 

16 """ 

17 constructor 

18 

19 @param code_func code (str) or function(func) 

20 """ 

21 TranslateClass.__init__(self, code_func) 

22 

23 def Signature(self, name, rows): 

24 """ 

25 Builds the signature of a function based 

26 on its name and its children. 

27 

28 @param name name 

29 @param rows list of arguments 

30 @return list of strings (code) 

31 """ 

32 code_rows = ["def {0}({1}):".format(name, ", ".join(rows))] 

33 return code_rows 

34 

35 def Select(self, name, table, rows): 

36 """ 

37 Interprets a select statement. 

38 

39 @param name name of the table which receives the results 

40 @param table name of the table it applies to 

41 @param rows rows to consider 

42 @return list of strings (code) 

43 """ 

44 code_rows = [] 

45 code_rows.append("{0} = [ ]".format(name)) 

46 code_rows.append("for row in {0}:".format(table)) 

47 

48 done = {} 

49 code_exp = [] 

50 code_exp.append(" newr = {") 

51 for r in rows: 

52 if r["type"] == "Attribute": 

53 tbl, att = r["str"].split(".") 

54 if tbl != table: 

55 self.RaiseCodeException( 

56 "an attribute comes from an unexpected table {0}!={1}".format( 

57 table, 

58 tbl)) 

59 if att not in done: 

60 code_rows.append(" _{0}=row['{0}']".format(att)) 

61 done[att] = att 

62 code_exp.append(" '{0}':_{0},".format(att)) 

63 elif r["type"] == "keyword": 

64 # it has to be an expression 

65 att0 = r["str"] 

66 exp, fields, functions = self.ResolveExpression(r, "_") 

67 

68 if len(functions) > 0: 

69 # we do nothing here, we assume the function is known 

70 # when it will be called 

71 pass 

72 

73 for att_ in fields: 

74 spl = att_.split(".") 

75 if len(spl) != 2: 

76 self.RaiseCodeException( 

77 "unexpected field name: " + 

78 att_) 

79 if spl[0] != table: 

80 self.RaiseCodeException( 

81 "unexpected table name: " + 

82 att_) 

83 att = spl[1] 

84 if att not in done: 

85 code_rows.append(" _{0}=row['{0}']".format(att)) 

86 done[att] = att 

87 exp = exp.replace(att_, att) 

88 code_exp.append(" '{0}':{1},".format(att0, exp)) 

89 else: 

90 self.RaiseCodeException("type expected {0}".format(r["type"])) 

91 r["processed"] = True 

92 

93 code_rows.extend(code_exp) 

94 code_rows.append(" }") 

95 code_rows.append(" {0}.append(newr)".format(name)) 

96 return [" " + _ for _ in code_rows] 

97 

98 def Where(self, name, table, rows): 

99 """ 

100 Interprets a where statement. 

101 

102 @param name name of the table which receives the results 

103 @param table name of the table it applies to 

104 @param rows rows to consider 

105 @return list of strings (code) 

106 """ 

107 code_rows = [] 

108 code_rows.append("{0} = [ ]".format(name)) 

109 code_rows.append("for row in {0}:".format(table)) 

110 

111 done = {} 

112 first = True 

113 for r in rows: 

114 if not first: 

115 self.RaiseCodeException( 

116 "SyntaxError, only one clause where is allowed") 

117 # att0 = r["str"] 

118 exp, fields, functions = self.ResolveExpression(r, "_") 

119 for att_ in fields: 

120 spl = att_.split(".") 

121 if len(spl) != 2: 

122 self.RaiseCodeException("unexpected field name: " + att_) 

123 if spl[0] != table: 

124 self.RaiseCodeException("unexpected table name: " + att_) 

125 att = spl[1] 

126 if att not in done: 

127 code_rows.append(" _{0}=row['{0}']".format(att)) 

128 done[att] = att 

129 exp = exp.replace(att_, att) 

130 code_rows.append(" _exp={0}".format(exp)) 

131 code_rows.append(" if _exp: {0}.append(row)".format(name)) 

132 r["processed"] = True 

133 first = False 

134 

135 return [" " + _ for _ in code_rows] 

136 

137 def setReturn(self, nodes): 

138 """ 

139 Indicates all nodes containing information about returned results. 

140 

141 @param nodes list of nodes 

142 @return list of string 

143 """ 

144 for node in nodes: 

145 node["processed"] = True 

146 names = [node["str"] for node in nodes] 

147 return [" return " + ",".join(names)] 

148 

149 def GroupBy(self, name, table, rows): 

150 """ 

151 Interprets a select statement. 

152 

153 @param name name of the table which receives the results 

154 @param table name of the table it applies to 

155 @param rows rows to consider 

156 @return list of strings (code) 

157 """ 

158 code_rows = [] 

159 code_rows.append("__groupby__ = {}") 

160 

161 keys = [] 

162 done = {} 

163 code_exp = [] 

164 loop_exp = [] 

165 agg_function = [] 

166 code_exp.append(" newr = {") 

167 for r in rows: 

168 if r["type"] == "Attribute": 

169 tbl, att = r["str"].split(".") 

170 if tbl != table: 

171 self.RaiseCodeException( 

172 "an attribute comes from an unexpected table {0}!={1}".format( 

173 table, 

174 tbl)) 

175 if att not in done: 

176 loop_exp.append(" _{0}=row['{0}']".format(att)) 

177 done[att] = att 

178 code_exp.append(" '{0}':_{0},".format(att)) 

179 keys.append(att) 

180 elif r["type"] == "keyword": 

181 #################### 

182 # it has to be an expression 

183 #################### 

184 att0 = r["str"] 

185 exp, fields, functions = self.ResolveExpression(r, "_") 

186 

187 if len(functions) > 0: 

188 # we do nothing here, we assume the function is known 

189 # when it will be called 

190 pass 

191 

192 for att_ in fields: 

193 spl = att_.split(".") 

194 if len(spl) != 1: 

195 self.RaiseCodeException( 

196 "unexpected field name: " + 

197 att_) 

198 funcname = att_ 

199 

200 chil = fields[att_]["children"] 

201 if len(chil) != 1: 

202 self.RaiseCodeException( 

203 "two many children: " + str(len(chil))) 

204 chil = chil[0] 

205 spl = chil["str"].split(".") 

206 if len(spl) != 2: 

207 self.RaiseCodeException( 

208 "unexpected field name: " + 

209 chil["str"]) 

210 table, att = spl 

211 chil["processed"] = True 

212 

213 if att not in done: 

214 loop_exp.append(" _{0}=row['{0}']".format(att)) 

215 code_exp.append(" '{0}':_{0},".format(att)) 

216 done[att] = att 

217 #exp = exp.replace(att_,att) 

218 agg_function.append((att0, funcname, table, att)) 

219 else: 

220 self.RaiseCodeException("type expected {0}".format(r["type"])) 

221 r["processed"] = True 

222 

223 code_rows.append( 

224 "keys = [ {0} ]".format( 

225 ",".join( 

226 '"{0}"'.format(k) for k in keys))) 

227 code_rows.append("for row in {0}:".format(table)) 

228 code_rows.extend(loop_exp) 

229 code_rows.extend(code_exp) 

230 code_rows.append(" }") 

231 allk = ",".join('_' + _ for _ in keys) 

232 code_rows.append(" _k_ = tuple( [ {0}, ] )".format(allk)) 

233 code_rows.append( 

234 " if _k_ not in __groupby__: __groupby__[_k_] = []") 

235 code_rows.append(" __groupby__[_k_].append( newr )") 

236 code_rows.append("") 

237 code_rows.append("{0} = [ ]".format(name)) 

238 

239 code_rows.append("for gr,rows in __groupby__.items():") 

240 code_rows.append(" r = {") 

241 for i, key in enumerate(keys): 

242 code_rows.append(" '{0}':gr[{1}],".format(key, i)) 

243 code_rows.append(" }") 

244 for newatt, funcname, tablel, att in agg_function: 

245 c = "[ d['{0}'] for d in rows ]".format(att) 

246 code_rows.append( 

247 " r['{0}'] = {1} ( {2} )".format(newatt, funcname, c)) 

248 code_rows.append(" iter.append( r )") 

249 

250 return [" " + _ for _ in code_rows]