def test_pattern_match(): r = match(assemble("$"), assemble("$")) assert r == {} r = match(assemble("($ . size)"), assemble("200")) assert r == {"size": assemble("200")} r = match(assemble("(: . size)"), assemble("200")) assert r == {"size": assemble("200")} r = match(assemble("($ . size)"), assemble("(I like cheese)")) assert r is None r = match(assemble("(: . size)"), assemble("(I like cheese)")) assert r == {"size": assemble("(I like cheese)")} r = match(assemble("(= (f (r (a))) ($ . pubkey))"), assemble("(= (f (r (a))) 50000)")) assert r == {"pubkey": assemble("50000")} r = match(assemble("(= (f (r (a))) ($ . pubkey1) ($ . pubkey2))"), assemble("(= (f (r (a))) 50000 60000)")) assert r == {"pubkey1": assemble("50000"), "pubkey2": assemble("60000")} r = match(assemble("(= (f (r (a))) ($ . pubkey1) ($ . pubkey1))"), assemble("(= (f (r (a))) 50000 60000)")) assert r is None r = match(assemble("(= (f (r (a))) ($ . pubkey1) ($ . pubkey1))"), assemble("(= (f (r (a))) 50000 50000)")) assert r == {"pubkey1": assemble("50000")}
def cons_optimizer(r, eval): """ This applies the transform (f (c A B)) => A and (r (c A B)) => B """ t1 = match(CONS_OPTIMIZER_PATTERN_FIRST, r) if t1: return t1["first"] t1 = match(CONS_OPTIMIZER_PATTERN_REST, r) if t1: return t1["rest"] return r
def var_change_optimizer_cons_eval(r, eval): """ This applies the transform ((c (q (op SEXP1...)) (ARGS))) => (q RET_VAL) where ARGS != @ via (op ((c SEXP1 (ARGS)) ...)) (ARGS)) and then "children_optimizer" of this. In some cases, this can result in a constant in some of the children. If we end up needing to push the "change of variables" to only one child, keep the optimization. Otherwise discard it. """ t1 = match(VAR_CHANGE_OPTIMIZER_CONS_EVAL_PATTERN, r) if t1 is None: return r original_args = t1["args"] if is_args_call(original_args): return r original_call = t1["sexp"] new_eval_sexp_args = sub_args(original_call, original_args) new_operands = list(new_eval_sexp_args.as_iter()) opt_operands = [optimize_sexp(_, eval) for _ in new_operands] non_constant_count = sum(1 if _.listp() and _.first() != QUOTE_KW else 0 for _ in opt_operands) if non_constant_count < 1: final_sexp = r.to(opt_operands) return final_sexp return r
def cons_q_a_optimizer(r, eval): """ This applies the transform (a (q . SEXP) @) => SEXP """ t1 = match(CONS_Q_A_OPTIMIZER_PATTERN, r) if t1 and is_args_call(t1["args"]): return t1["sexp"] return r
def apply_null_optimizer(r, eval): """ This applies the transform `(a 0 ARGS)` => `0` """ t1 = match(APPLY_NULL_PATTERN_1, r) if t1 is not None: return r.to(0) return r
def quote_null_optimizer(r, eval): """ This applies the transform `(q . 0)` => `0` """ t1 = match(QUOTE_PATTERN_1, r) if t1 is not None: return r.to(0) return r
def path_optimizer(r, eval): """ This applies the transform (f N) => A and (r N) => B """ t1 = match(FIRST_ATOM_PATTERN, r) if t1 and non_nil(t1["atom"]): node = NodePath(t1["atom"].as_int()) node = node + LEFT return r.to(node.as_short_path()) t1 = match(REST_ATOM_PATTERN, r) if t1 and non_nil(t1["atom"]): node = NodePath(t1["atom"].as_int()) node = node + RIGHT return r.to(node.as_short_path()) return r
def path_optimizer(r, eval): """ This applies the transform (a) => 1 and (f N) => A and (r N) => B """ if is_args_call(r): return r.to(1) t1 = match(FIRST_ATOM_PATTERN, r) if t1: node = NodePath(t1["atom"].as_int()) node = node + LEFT return r.to(node.as_short_path()) t1 = match(REST_ATOM_PATTERN, r) if t1: node = NodePath(t1["atom"].as_int()) node = node + RIGHT return r.to(node.as_short_path()) return r
def cons_r(args): t = match(CONS_PATTERN, args) if t: return t["rest"] return args.to([REST_KW, args])
def cons_f(args): t = match(CONS_PATTERN, args) if t: return t["first"] return args.to([FIRST_KW, args])