def test_as_clauses_basic(self) -> None: ios = [ ('true', ['true | false']), ('foo', ['foo | false']), ('forall N1,N2. grant_msg(N1) & grant_msg(N2) -> N1 = N2', ['forall N1, N2. !grant_msg(N1) | !grant_msg(N2) | N1 = N2']), ('forall N1,N2. !(holds_lock(N1) & grant_msg(N2))', ['forall N1, N2. !holds_lock(N1) | !grant_msg(N2)']), ('forall N. !(unlock_msg(N) & server_holds_lock)', ['forall N. !unlock_msg(N) | !server_holds_lock']), ('!(exists N. holds_lock(N) & server_holds_lock)', ['forall N. !holds_lock(N) | !server_holds_lock']), ('!!(forall X. !(exists Y. (r(X) & s(Y)) & (q(X) & p(Y))))', ['forall X, Y. !r(X) | !s(Y) | !q(X) | !p(Y)']), ('forall X. r(X) & s(X)', ['forall X. r(X) | false', 'forall X. s(X) | false']), ('forall X. (r(X) | s(X)) & (q(X) | p(X))', ['forall X. r(X) | s(X)', 'forall X. q(X) | p(X)']), ] for expr, expected in ios: with self.subTest(expr=expr): clauses = syntax.as_clauses(parser.parse_expr(expr)) # print(clause) self.assertEqual(clauses, [ parser.parse_expr(expected_clause) for expected_clause in expected ])
def test_relativize_quantifiers(self) -> None: minipaxos = ''' sort node sort quorum immutable relation member(node, quorum) mutable relation active_node(node) mutable relation active_quorum(quorum) ''' prog = mypyvy.parse_program(minipaxos) typechecker.typecheck_program(prog) node = prog.scope.get_sort('node') assert node is not None quorum = prog.scope.get_sort('quorum') assert quorum is not None active_node = prog.scope.get('active_node') assert isinstance(active_node, syntax.RelationDecl) active_quorum = prog.scope.get('active_quorum') assert isinstance(active_quorum, syntax.RelationDecl) guards = {node: active_node, quorum: active_quorum} e = parser.parse_expr('forall Q1, Q2. exists N. member(N, Q1) & member(N, Q2)') typechecker.typecheck_expr(prog.scope, e, None) expected = parser.parse_expr('forall Q1, Q2. active_quorum(Q1) & active_quorum(Q2) -> ' 'exists N. active_node(N) & (member(N, Q1) & member(N, Q2))') with prog.scope.n_states(1): typechecker.typecheck_expr(prog.scope, expected, None) self.assertEqual(syntax.relativize_quantifiers(guards, e), expected)
def test_parser_bool_expr(self): b1a = "(x == 1)" self.assertEqual(parse_expr(b1a), BoolArithCmp( ArithCmp.Eq, Var("x"), ArithLit(1))) b4 = "(x > 1) && (y < 0)" self.assertEqual(parse_expr(b4), BoolBinop( BoolOp.And, BoolArithCmp( ArithCmp.Gt, Var("x"), ArithLit(1)), BoolArithCmp( ArithCmp.Lt, Var("y"), ArithLit(0)))) b4a = "x > 1 && y < 0" self.assertEqual(parse_expr(b4a), BoolBinop( BoolOp.And, BoolArithCmp( ArithCmp.Gt, Var("x"), ArithLit(1)), BoolArithCmp( ArithCmp.Lt, Var("y"), ArithLit(0)))) b5 = "(x > 1) || (y < 0)" self.assertEqual(parse_expr(b5), BoolBinop( BoolOp.Or, BoolArithCmp( ArithCmp.Gt, Var("x"), ArithLit(1)), BoolArithCmp( ArithCmp.Lt, Var("y"), ArithLit(0)))) b5a = "x > 1 || y < 0" self.assertEqual(parse_expr(b5a), BoolBinop( BoolOp.Or, BoolArithCmp( ArithCmp.Gt, Var("x"), ArithLit(1)), BoolArithCmp( ArithCmp.Lt, Var("y"), ArithLit(0))))
def test_non_balanced_expr(self): inputs = [ ")", "(1", "(1 + ()", ] for input in inputs: with self.subTest(i = input): with self.assertRaises(Exception): parse_expr(input)
def lambda_handler(event, context): statement_sources = event['statements'] statements = [ Eq(parse_expr(s[0]), parse_expr(s[1])) for s in statement_sources ] knowns, unknowns = solve(statements) ret = { "known": {}, "unknown": {}, } for symbol, value in knowns.iteritems(): if type(value) is not tuple: value = (value,) ret["known"][latex(symbol)] = { "results": [ { "float": latex(possibility.evalf()), "rational": latex(possibility), } for possibility in value ], } for symbol, resolutions in unknowns.iteritems(): ret["unknown"][latex(symbol)] = { "resolutions": [ { "dependencies": [ latex(dep_symbol) for dep_symbol in resolution.required_symbols ], "solutions": [ latex(solution) for solution in ( resolution.rhs if type(resolution.rhs) is list else [resolution.rhs,] ) ], } for resolution in resolutions ], } return ret
def get_safety() -> List[Expr]: prog = syntax.the_program safety: List[Expr] if utils.args.safety is not None: the_inv: Optional[InvariantDecl] = None for inv in prog.invs(): if inv.name == utils.args.safety: the_inv = inv if the_inv is not None: safety = [the_inv.expr] else: try: oldcount = utils.error_count e = syntax.close_free_vars(parser.parse_expr( utils.args.safety)) with prog.scope.n_states(1): typechecker.typecheck_expr(prog.scope, e, syntax.BoolSort) assert oldcount == utils.error_count, 'errors in parsing or typechecking' safety = [e] except Exception as e: print(e) utils.print_error_and_exit( None, f'--safety received string "{utils.args.safety}", ' 'which is neither the name of an invariant/safety property ' 'nor does it parse and typecheck as an expression') else: safety = [s.expr for s in prog.safeties()] return safety
def eval_ast (expr, gl=None, lc=None): """ Provide an 'eval' function which is identical to the builtin 'eval'. The thing is that the expression will be evaluated on the AST nodes (dynamic languages cool or what?), without the generation of any bytecode objects. The existance of an 'eval' function that can evaluate code objects is required though (this is not pure in terms of 'no virtual machine that can execute python bytecode is required'). The reason is that for loops (list comprehensions, generator expressions) we'd rather evaluate it in bytecode which is faster. """ if gl: if lc: def lookup_name (x): if x in l: return lc [x] if x in gl: return gl [x] return __builtins__ [x] def lookup_name (x): try: return gl [x] except: return __builtins__ [x] else: def lookup_name (x): return __builtins__ [x] GCO.new_compiler () GCO ['eval_lookup'] = lookup_name GCO ['py2ext'] = False GCO ['dynlocals'] = True GCO ['gnt'] = False GCO ['gnc'] = False GCO ['filename'] = '*eval*' GCO ['docstrings'] = True try: return parser.parse_expr (source=expr).eval () finally: GCO.pop_compiler ()
def test_parse_expr_pointers(self): inputs = [ ("*n + 1", ArithBinop( ArithOp.Add, ArithUnaryop( ArithUnaryOp.Deref, Var("n")), ArithLit(1) )), ("1 + *n", ArithBinop( ArithOp.Add, ArithLit(1), ArithUnaryop( ArithUnaryOp.Deref, Var("n")) )), ("*n + *m", ArithBinop( ArithOp.Add, ArithUnaryop( ArithUnaryOp.Deref, Var("n")), ArithUnaryop( ArithUnaryOp.Deref, Var("m")) )) ] for (input, expected) in inputs: with self.subTest(input=input): self.assertEqual( parse_expr(input), expected)
def to_tree(expr:str): ast = parse_expr(expr) #print(ast.str_tree()) decorate(ast) decorate_bindings(ast) ast = substitute_macros(ast) decorate(ast) return ast
def test_parser_expr_deref(self): input = "&n" self.assertEqual(parse_expr(input), ArithUnaryop( ArithUnaryOp.Addr, Var("n") ))
def test_as_clauses_fail(self) -> None: egs = [ 'exists X. X = X', ] for expr in egs: with self.subTest(expr=expr): with self.assertRaises(Exception): print(syntax.as_clauses(parser.parse_expr(expr)))
def compile(source, filename, mode, flags=None, dont_inherit=None, py2ext=False, dynlocals=True, showmarks=False, ConstDict=None, RRot3=False, asserts=True, nolno=False): """Replacement for builtin compile() function""" if flags is not None or dont_inherit is not None: raise RuntimeError, "not implemented yet" ConstDict = None GCO.new_compiler () GCO ['Asserts'] = asserts GCO ['dynlocals'] = dynlocals GCO ['gnt'] = False GCO ['gnc'] = False GCO ['showmarks'] = showmarks GCO ['rrot3'] = RRot3 GCO ['py2ext'] = py2ext GCO ['filename'] = filename and os.path.abspath (filename) or '*eval*' GCO ['arch'] = get_version () GCO ['lnotab'] = not nolno GCO ['pyvm'] = sys.copyright.startswith ('pyvm') GCO ['docstrings'] = True try: if mode == "exec": if not source: tree = parser.parse (filename=filename) else: # ??? tree = parser.parse (filename=filename, source=source) transform_tree (tree) if GCO ['have_with']: tree.Import ('sys') if ConstDict: constify_names (tree, ConstDict) pyc_constants (tree) parseSymbols (tree) optimize_tree (tree) elif mode == "eval": tree = ast.Expression (parser.parse_expr (source)) transform_tree (tree) pyc_constants (tree) parseSymbols (tree) elif mode == "single": # XXX pass an iterator from which it can read more lines! tree = parser.parse (source=source) if GCO ['have_with']: tree.Import ('sys') transform_tree (tree) pyc_constants (tree) parseSymbols (tree) else: raise ValueError("compile() 3rd arg must be 'exec' or " "'eval' or 'single'") return ast2code (tree, mode) finally: GCO.pop_compiler ()
def parse_and_typecheck_expr(input: str, n_states: int = 0, close_free_vars: bool = False) -> syntax.Expr: e = parser.parse_expr(input) if close_free_vars: e = syntax.close_free_vars(e, span=e.span) scope = syntax.the_program.scope with scope.n_states(n_states): typechecker.typecheck_expr(scope, e, None) return e
def test_parser_bool(self): b1 = "x == 1" self.assertEqual(parse_expr(b1), BoolArithCmp( ArithCmp.Eq, Var("x"), ArithLit(1))) b2 = "x != 1" self.assertEqual(parse_expr(b2), BoolArithCmp( ArithCmp.Neq, Var("x"), ArithLit(1))) b3 = "x > 1" self.assertEqual(parse_expr(b3), BoolArithCmp( ArithCmp.Gt, Var("x"), ArithLit(1)))
def test_parser_expr_funcall(self): e1 = "foo()" r1 = FunCall("foo", []) self.assertEqual(parse_expr(e1), r1) e2 = "foo(1)" r2 = FunCall("foo", [ArithLit(1)]) self.assertEqual(parse_expr(e2), r2) e3 = "foo(1,2)" r3 = FunCall("foo", [ArithLit(1), ArithLit(2)]) self.assertEqual(parse_expr(e3), r3) e4 = "2 + foo()" r4 = ArithBinop(ArithOp.Add, ArithLit(2), FunCall("foo", [])) self.assertEqual(parse_expr(e4), r4) e5 = "2 + foo() > 4" r5 = BoolArithCmp(ArithCmp.Gt, r4, ArithLit(4)) self.assertEqual(parse_expr(e5), r5) e6 = "foo(x, y, bar())" r6 = FunCall("foo", [Var("x"), Var("y"), FunCall("bar", [])]) self.assertEqual(parse_expr(e6), r6)
def _recover(): with open('cache.txt', 'r') as f: lines = f.readlines() population = [] for line in lines: if line.strip() == '': continue r_expr, mse = line.strip().split(';') parsed, expr = parse_expr(r_expr) if not parsed: continue population.append((expr, float(mse))) return population
def get_safety() -> List[Expr]: prog = syntax.the_program safety: List[Expr] if utils.args.safety is not None: the_inv: Optional[InvariantDecl] = None for inv in prog.invs(): if inv.name == utils.args.safety: the_inv = inv if the_inv is not None: safety = [the_inv.expr] else: e = syntax.close_free_vars(None, parser.parse_expr(utils.args.safety)) e.resolve(prog.scope, syntax.BoolSort) safety = [e] else: safety = [s.expr for s in prog.safeties()] return safety
def eval_expr(expr_str, show_tokens=False, showast=False, showgrammar=False, compile_mode='exec'): """ evaluate simple expression """ parser_debug = {'rules': False, 'transition': False, 'reduce': showgrammar, 'errorstack': True, 'context': True } parsed = parse_expr(expr_str, show_tokens=show_tokens, parser_debug=parser_debug) if showast: print (parsed) assert parsed == 'expr', 'Should have parsed grammar start' evaluator = ExprEvaluator() # What we've been waiting for: Generate source from AST! return evaluator.traverse(parsed)
def eval_expr(expr_str, show_tokens=False, showast=False, showgrammar=False, compile_mode='exec'): """ evaluate simple expression """ parser_debug = {'rules': False, 'transition': False, 'reduce': showgrammar, 'errorstack': True, 'context': True } parsed = parse_expr(expr_str, show_tokens=show_tokens, parser_debug=parser_debug) if showast: print(parsed) assert parsed == 'expr', 'Should have parsed grammar start' evaluator = ExprEvaluator() # What we've been waiting for: Generate source from AST! return evaluator.traverse(parsed)
def eval_ast(expr, gl=None, lc=None): """ Provide an 'eval' function which is identical to the builtin 'eval'. The thing is that the expression will be evaluated on the AST nodes (dynamic languages cool or what?), without the generation of any bytecode objects. The existance of an 'eval' function that can evaluate code objects is required though (this is not pure in terms of 'no virtual machine that can execute python bytecode is required'). The reason is that for loops (list comprehensions, generator expressions) we'd rather evaluate it in bytecode which is faster. """ if gl: if lc: def lookup_name(x): if x in l: return lc[x] if x in gl: return gl[x] return __builtins__[x] def lookup_name(x): try: return gl[x] except: return __builtins__[x] else: def lookup_name(x): return __builtins__[x] GCO.new_compiler() GCO['eval_lookup'] = lookup_name GCO['py2ext'] = False GCO['dynlocals'] = True GCO['gnt'] = False GCO['gnc'] = False GCO['filename'] = '*eval*' GCO['docstrings'] = True try: return parser.parse_expr(source=expr).eval() finally: GCO.pop_compiler()
def compile(source, filename, mode, flags=None, dont_inherit=None, py2ext=False, dynlocals=True, showmarks=False, ConstDict=None, RRot3=False, asserts=True, nolno=False): """Replacement for builtin compile() function""" if flags is not None or dont_inherit is not None: raise RuntimeError, "not implemented yet" ConstDict = None GCO.new_compiler() GCO['Asserts'] = asserts GCO['dynlocals'] = dynlocals GCO['gnt'] = False GCO['gnc'] = False GCO['showmarks'] = showmarks GCO['rrot3'] = RRot3 GCO['py2ext'] = py2ext GCO['filename'] = filename and os.path.abspath(filename) or '*eval*' GCO['arch'] = get_version() GCO['lnotab'] = not nolno GCO['pyvm'] = sys.copyright.startswith('pyvm') GCO['docstrings'] = True try: if mode == "exec": if not source: tree = parser.parse(filename=filename) else: # ??? tree = parser.parse(filename=filename, source=source) transform_tree(tree) if GCO['have_with']: tree.Import('sys') if ConstDict: constify_names(tree, ConstDict) pyc_constants(tree) parseSymbols(tree) optimize_tree(tree) elif mode == "eval": tree = ast.Expression(parser.parse_expr(source)) transform_tree(tree) pyc_constants(tree) parseSymbols(tree) elif mode == "single": # XXX pass an iterator from which it can read more lines! tree = parser.parse(source=source) if GCO['have_with']: tree.Import('sys') transform_tree(tree) pyc_constants(tree) parseSymbols(tree) else: raise ValueError("compile() 3rd arg must be 'exec' or " "'eval' or 'single'") return ast2code(tree, mode) finally: GCO.pop_compiler()
def load_relaxed_trace_from_updr_cex(prog: Program, s: Solver) -> logic.Trace: import xml.dom.minidom # type: ignore collection = xml.dom.minidom.parse( "paxos_derived_trace.xml").documentElement components: List[syntax.TraceComponent] = [] xml_decls = reversed(collection.childNodes) seen_first = False for elm in xml_decls: if isinstance(elm, xml.dom.minidom.Text): # type: ignore continue if elm.tagName == 'state': diagram = parser.parse_expr(elm.childNodes[0].data) typechecker.typecheck_expr(prog.scope, diagram, syntax.BoolSort) assert isinstance( diagram, syntax.QuantifierExpr) and diagram.quant == 'EXISTS' active_clauses = [ relaxed_traces.active_var(v.name, str(v.sort)) for v in diagram.get_vs() ] if not seen_first: # restrict the domain to be subdomain of the diagram's existentials seen_first = True import itertools # type: ignore for sort, vars in itertools.groupby( diagram.get_vs(), lambda v: v.sort): # TODO; need to sort first free_var = syntax.SortedVar( syntax.the_program.scope.fresh("v_%s" % str(sort)), None) # TODO: diagram simplification omits them from the exists somewhere consts = list( filter(lambda c: c.sort == sort, prog.constants())) els: Sequence[Union[syntax.SortedVar, syntax.ConstantDecl]] els = list(vars) els += consts restrict_domain = syntax.Forall( (free_var, ), syntax.Or(*(syntax.Eq(syntax.Id(free_var.name), syntax.Id(v.name)) for v in els))) active_clauses += [restrict_domain] diagram_active = syntax.Exists( diagram.get_vs(), syntax.And(diagram.body, *active_clauses)) typechecker.typecheck_expr(prog.scope, diagram_active, syntax.BoolSort) components.append(syntax.AssertDecl(expr=diagram_active)) elif elm.tagName == 'action': action_name = elm.childNodes[0].data.split()[0] tcall = syntax.TransitionCalls( calls=[syntax.TransitionCall(target=action_name, args=None)]) components.append(syntax.TraceTransitionDecl(transition=tcall)) else: assert False, "unknown xml tagName" trace_decl = syntax.TraceDecl(components=components, sat=True) migrated_trace = bmc_trace( prog, trace_decl, s, lambda s, ks: logic.check_solver(s, ks, minimize=True), log=False) assert migrated_trace is not None import pickle pickle.dump(migrated_trace, open("migrated_trace.p", "wb")) return migrated_trace