"""
One class which visits a syntax tree.
:githublink:`%|py|5`
"""
from .translation_class import TranslateClass
[docs]class Translate2Python(TranslateClass):
"""
Translates a code into :epkg:`Python`.
:githublink:`%|py|13`
"""
[docs] def __init__(self, code_func):
"""
constructor
:param code_func: code (str) or function(func)
:githublink:`%|py|20`
"""
TranslateClass.__init__(self, code_func)
[docs] def Signature(self, name, rows):
"""
Builds the signature of a function based
on its name and its children.
:param name: name
:param rows: list of arguments
:return: list of strings (code)
:githublink:`%|py|31`
"""
code_rows = ["def {0}({1}):".format(name, ", ".join(rows))]
return code_rows
[docs] def Select(self, name, table, rows):
"""
Interprets a select statement.
:param name: name of the table which receives the results
:param table: name of the table it applies to
:param rows: rows to consider
:return: list of strings (code)
:githublink:`%|py|43`
"""
code_rows = []
code_rows.append("{0} = [ ]".format(name))
code_rows.append("for row in {0}:".format(table))
done = {}
code_exp = []
code_exp.append(" newr = {")
for r in rows:
if r["type"] == "Attribute":
tbl, att = r["str"].split(".")
if tbl != table:
self.RaiseCodeException(
"an attribute comes from an unexpected table {0}!={1}".format(
table,
tbl))
if att not in done:
code_rows.append(" _{0}=row['{0}']".format(att))
done[att] = att
code_exp.append(" '{0}':_{0},".format(att))
elif r["type"] == "keyword":
# it has to be an expression
att0 = r["str"]
exp, fields, functions = self.ResolveExpression(r, "_")
if len(functions) > 0:
# we do nothing here, we assume the function is known
# when it will be called
pass
for att_ in fields:
spl = att_.split(".")
if len(spl) != 2:
self.RaiseCodeException(
"unexpected field name: " +
att_)
if spl[0] != table:
self.RaiseCodeException(
"unexpected table name: " +
att_)
att = spl[1]
if att not in done:
code_rows.append(" _{0}=row['{0}']".format(att))
done[att] = att
exp = exp.replace(att_, att)
code_exp.append(" '{0}':{1},".format(att0, exp))
else:
self.RaiseCodeException("type expected {0}".format(r["type"]))
r["processed"] = True
code_rows.extend(code_exp)
code_rows.append(" }")
code_rows.append(" {0}.append(newr)".format(name))
return [" " + _ for _ in code_rows]
[docs] def Where(self, name, table, rows):
"""
Interprets a where statement.
:param name: name of the table which receives the results
:param table: name of the table it applies to
:param rows: rows to consider
:return: list of strings (code)
:githublink:`%|py|106`
"""
code_rows = []
code_rows.append("{0} = [ ]".format(name))
code_rows.append("for row in {0}:".format(table))
done = {}
first = True
for r in rows:
if not first:
self.RaiseCodeException(
"SyntaxError, only one clause where is allowed")
# att0 = r["str"]
exp, fields, functions = self.ResolveExpression(r, "_")
for att_ in fields:
spl = att_.split(".")
if len(spl) != 2:
self.RaiseCodeException("unexpected field name: " + att_)
if spl[0] != table:
self.RaiseCodeException("unexpected table name: " + att_)
att = spl[1]
if att not in done:
code_rows.append(" _{0}=row['{0}']".format(att))
done[att] = att
exp = exp.replace(att_, att)
code_rows.append(" _exp={0}".format(exp))
code_rows.append(" if _exp: {0}.append(row)".format(name))
r["processed"] = True
first = False
return [" " + _ for _ in code_rows]
[docs] def setReturn(self, nodes):
"""
Indicates all nodes containing information about returned results.
:param nodes: list of nodes
:return: list of string
:githublink:`%|py|143`
"""
for node in nodes:
node["processed"] = True
names = [node["str"] for node in nodes]
return [" return " + ",".join(names)]
[docs] def GroupBy(self, name, table, rows):
"""
Interprets a select statement.
:param name: name of the table which receives the results
:param table: name of the table it applies to
:param rows: rows to consider
:return: list of strings (code)
:githublink:`%|py|157`
"""
code_rows = []
code_rows.append("__groupby__ = {}")
keys = []
done = {}
code_exp = []
loop_exp = []
agg_function = []
code_exp.append(" newr = {")
for r in rows:
if r["type"] == "Attribute":
tbl, att = r["str"].split(".")
if tbl != table:
self.RaiseCodeException(
"an attribute comes from an unexpected table {0}!={1}".format(
table,
tbl))
if att not in done:
loop_exp.append(" _{0}=row['{0}']".format(att))
done[att] = att
code_exp.append(" '{0}':_{0},".format(att))
keys.append(att)
elif r["type"] == "keyword":
####################
# it has to be an expression
####################
att0 = r["str"]
exp, fields, functions = self.ResolveExpression(r, "_")
if len(functions) > 0:
# we do nothing here, we assume the function is known
# when it will be called
pass
for att_ in fields:
spl = att_.split(".")
if len(spl) != 1:
self.RaiseCodeException(
"unexpected field name: " +
att_)
funcname = att_
chil = fields[att_]["children"]
if len(chil) != 1:
self.RaiseCodeException(
"two many children: " + str(len(chil)))
chil = chil[0]
spl = chil["str"].split(".")
if len(spl) != 2:
self.RaiseCodeException(
"unexpected field name: " +
chil["str"])
table, att = spl
chil["processed"] = True
if att not in done:
loop_exp.append(" _{0}=row['{0}']".format(att))
code_exp.append(" '{0}':_{0},".format(att))
done[att] = att
#exp = exp.replace(att_,att)
agg_function.append((att0, funcname, table, att))
else:
self.RaiseCodeException("type expected {0}".format(r["type"]))
r["processed"] = True
code_rows.append(
"keys = [ {0} ]".format(
",".join(
'"{0}"'.format(k) for k in keys)))
code_rows.append("for row in {0}:".format(table))
code_rows.extend(loop_exp)
code_rows.extend(code_exp)
code_rows.append(" }")
allk = ",".join('_' + _ for _ in keys)
code_rows.append(" _k_ = tuple( [ {0}, ] )".format(allk))
code_rows.append(
" if _k_ not in __groupby__: __groupby__[_k_] = []")
code_rows.append(" __groupby__[_k_].append( newr )")
code_rows.append("")
code_rows.append("{0} = [ ]".format(name))
code_rows.append("for gr,rows in __groupby__.items():")
code_rows.append(" r = {")
for i, key in enumerate(keys):
code_rows.append(" '{0}':gr[{1}],".format(key, i))
code_rows.append(" }")
for newatt, funcname, tablel, att in agg_function:
c = "[ d['{0}'] for d in rows ]".format(att)
code_rows.append(
" r['{0}'] = {1} ( {2} )".format(newatt, funcname, c))
code_rows.append(" iter.append( r )")
return [" " + _ for _ in code_rows]