Source code for pyidp3.idp_py_syntax
#idp_py_syntax
def flatten(l, ltypes=(list, tuple)):
ltype = type(l)
l = list(l)
i = 0
while i < len(l):
while isinstance(l[i], ltypes):
if not l[i]:
l.pop(i)
i -= 1
break
else:
l[i:i + 1] = l[i]
i += 1
return ltype(l)
class Formula(object):
pass
def tuple_to_atom(tup):
try:
typing = tup[1] + "(" + ", ".join(map(str,tup[0])) + ")"
except TypeError:
typing = tup[1] + "(" + tup[0] + ")"
if len(tup) >= 3 and len(tup[2]) >= 1:
ifs = " & ".join(map(str,tup[2]))
return typing + " & " + ifs
else:
return typing
class DefRule(Formula):
def __init__(self, args, body):
self.args = args
self.body = body
def __str__(self):
return "(" + ", ".join(self.args) + ")" + " <- " + str(self.body) + "."
class AggregateFormula(Formula):
def __init__(self, agg, vars, formula):
self.agg = agg
self.vars = vars
self.formula = formula
def __str__(self):
var_tuple = flatten([x[0] for x in self.vars])
it = (" ".join(var_tuple) + ": " +
" & ".join(map(tuple_to_atom, self.vars)))
if self.agg == "card":
return self.agg + "{" + it + " }"
return self.agg + "{" + it + " : " + str(self.formula) + "}"
class ArithmeticFormula(Formula):
def __init__(self,symbol,children):
self.symbol = symbol
self.children = children
def __str__(self):
def add_pars(x):
symbols = "+-*%/^"
return "(" + x + ")" if any([(s in x) for s in symbols]) else x
if self.symbol == "/":
(l,r) = [add_pars(str(x)) for x in self.children]
return "(" + l + "-" + l + "%" + r + ") / " + r
else:
return (" " + self.symbol + " ").join([add_pars(str(x)) for x in self.children])
class BooleanFormula(Formula):
def __init__(self,symbol,children):
self.symbol = symbol
self.children = children
def __str__(self):
return (" " + self.symbol + " ").join(["(" + str(x) + ")" for x in self.children])
class UnaryFormula(Formula):
def __init__(self,symb,child):
self.child = child
self.symb = symb
def __str__(self):
return self.symb + "(" + str(self.child) + ")"
class QuantifiedFormula(Formula):
def __init__(self, kind, vars, formula):
self.kind = kind
self.vars = vars
self.formula = formula
def guard_sym(self):
if self.kind == "!":
return "=>"
if self.kind == "?":
return "&"
def __str__(self):
var_tuple = flatten([x[0] for x in self.vars])
return (self.kind + " " + " ".join(var_tuple) + ": " +
" & ".join(map(tuple_to_atom, self.vars)) +
self.guard_sym() + " "+ str(self.formula))
class Comparison(Formula):
def __init__(self,symb,left,right):
self.symb = symb
self.left = left
self.right = right
def __str__(self):
return str(self.left) + " " + self.symb + " " + str(self.right)
import ast
[docs]class FormulaBuilder(ast.NodeVisitor):
def __init__(self):
pass
[docs] def generic_visit(self, node):
result = flatten([self.visit(child) for child in ast.iter_child_nodes(node)])
return result
def visit_BinOp(self, node):
symb = self.visit(node.op)
return ArithmeticFormula(symb, [self.visit(node.left), self.visit(node.right)])
def visit_BoolOp(self, node):
symb = self.visit(node.op)
return BooleanFormula(symb, [self.visit(child) for child in node.values])
def visit_Add(self, node): return "+"
def visit_Sub(self, node): return "-"
def visit_Mult(self, node): return "*"
def visit_Div(self, node): return "/"
def visit_Mod(self, node): return "%"
def visit_Pow(self, node): return "^"
def visit_Num(self, node):
return str(node.n)
def visit_And(self, node):
return "&"
def visit_Or(self, node):
return "|"
def visit_Not(self, node):
return "~"
def visit_Eq(self, node):
return "="
def visit_NotEq(self, node):
return "~="
def visit_Lt(self, node):
return "<"
def visit_Gt(self, node):
return ">"
def visit_LtE(self, node):
return "=<"
def visit_GtE(self, node):
return ">="
def visit_Compare(self, node):
return Comparison(self.visit(node.ops[0]), self.visit(node.left), self.visit(node.comparators[0]))
def visit_UnaryOp(self, node):
symb = self.visit(node.op)
return UnaryFormula(symb, self.visit(node.operand))
def visit_Tuple(self, node):
return tuple([self.visit(x) for x in node.elts])
def visit_GeneratorExp(self,node):
return self.visit_ListComp(node)
def visit_ListComp(self,node):
return ([(self.visit(gen.target), self.visit(gen.iter), [self.visit(an_if) for an_if in gen.ifs]) for gen in node.generators], self.visit(node.elt))
def visit_Name(self, node):
return node.id
def visit_Lambda(self, node):
return DefRule(self.visit(node.args), self.visit(node.body))
def visit_Call(self, node):
func = self.visit(node.func)
if func == "any" or func == "all":
symb = "?" if func == "any" else "!"
return QuantifiedFormula(symb, *self.visit(node.args[0]))
aggregates = { 'sum' : 'sum', 'len' : 'card', 'product' : 'prod', 'max' : 'max', 'min' : 'min' }
if func in list(aggregates.keys()):
return AggregateFormula(aggregates[func], *self.visit(node.args[0]))
return str(func) + "(" + ", ".join(map(str, [self.visit(arg) for arg in node.args])) + ")"
def parse(string):
import ast
p = ast.parse(string)
return FormulaBuilder().visit(p)[0]
def parse_formula(string):
result = parse(string)
return str(result)