def visit_Compound(self, node: Compound): node.env = Environment(merge_with=node.env) for i, d in node.children(): d.env = node.env d.global_env = node.global_env self.visit(d)
def clause_simpagation(env, p): name = Compound(env.getatom(p[0].getstr(), 0), []) keep = unbox(p[2]) drop = unbox(p[4]) guard = unbox(p[5]) goal = unbox(p[7]) return Box(Compound(env.getatom('constraint_rule', 5), [name, keep, drop, guard, goal]))
def chr_add_constraint(goal, mach, program): assert isinstance(goal, Compound) chrid = mach.next_chrid mach.next_chrid += 1 mach.chr_add_constraint(chrid, goal) deep_freeze(mach, goal, Compound(CHR_REVISE, [wrap(chrid)])) #print 'start resolution: %d %s' % (chrid, goal.stringify()) # Without locking the database, we'd lose track # of constraints added and removed and # the constraint resolution step would fail. assert not mach.chr_lock mach.chr_lock = True constraint_resolution(goal.fsym, chrid, mach, program) mach.chr_lock = False
def load(code, varno=100, debug=False): defs = {} chrs = [] constraints = {} occurrenceno = 0 for clause in reversed(as_list(code)): assert isinstance(clause, Compound) if clause.fsym is CLAUSE: head = clause.args[0] assert isinstance(head, Compound) if head.fsym in defs: rest = defs[head.fsym] else: rest = Compound(NIL, []) defs[head.fsym] = Compound(CONS, [clause, rest]) elif clause.fsym is CONSTRAINT_RULE: name = clause.args[0] assert isinstance(name, Compound) name = name.fsym.name keep = as_list(clause.args[1]) drop = as_list(clause.args[2]) guard = clause.args[3] goal = clause.args[4] this = CHR(name, keep + drop, len(keep), guard, goal) chrs.append(this) index = 0 for k in this.pattern: assert isinstance(k, Compound) if k.fsym in constraints: constraints[k.fsym].insert(0, (this, index)) else: constraints[k.fsym] = [(this, index)] index += 1 else: raise ValueError("machine.load received a non-program") return Program(defs, constraints)
def constraint_resolution(fsym, chrid, mach, program, start=0): constraints = program.constraints.get(fsym, []) for rule, pivot in constraints[start:]: #print 'checking rule %s:%d' % (rule.name, pivot) memo = execute_rule(rule, pivot, chrid, mach, program) if memo is not None: goal = mach.variant(rule.goal, memo) #print 'success: ' + goal.stringify() if rule.keep <= pivot: # The constraint did not survive. return mach.state.expand([goal]) if start + 1 >= len(constraints): return mach.state.expand([goal]) return mach.state.expand( [goal, Compound(CHR_RESUME, [wrap(chrid), wrap(start + 1)])]) start += 1
def main(argv): if len(argv) <= 1: return 1 fd = rfile.create_file(argv[1], 'rb') try: source = fd.read() finally: fd.close() code, next_varno = parser.parse(source) program = machine.load(code) succ = machine.Success() try: program.solve(succ, Compound(MAIN, []), next_varno) except machine.Exiting as exit: return exit.status return 0
def solve(mach, program, debug=False): goal = mach.state.next_goal(mach) while goal is not None: if debug: print for _, a in mach.state.disj: print " " + a.stringify() print "** " + goal.stringify() + "#" + mach.state.conj.stringify() if goal.fsym is TRUE: pass elif goal.fsym is FALSE: mach.state.fail() elif goal.fsym is AND: car = goal.args[0] cdr = goal.args[1] mach.state.expand([car, cdr]) elif goal.fsym is OR: car = goal.args[0] cdr = goal.args[1] mach.state.choicepoint(mach, [cdr]) mach.state.invoke(car) elif goal.fsym is SAME: car = goal.args[0] cdr = goal.args[1] if not car.same(cdr): mach.state.fail() elif goal.fsym is UNIFY: left = goal.args[0] right = goal.args[1] if not mach.unify(left, right): mach.state.fail() # I wonder if this is still required, or if it should be improved. elif goal.fsym is COND2: mach.backtrack += 1 t = mach.note() csucc = CondSuccess() cgoal = goal.args[0] cconj = goal.args[1] this_state = mach.state mach.state = mach.state.subgoal(cgoal, [], csucc) solve(mach, program, debug) mach.state = this_state mach.backtrack -= 1 if csucc.success: mach.state.invoke(cconj) else: mach.undo(t) elif goal.fsym is GET_ATTS: var = goal.args[0] spec = goal.args[1] assert isinstance(spec, Compound) val = var.attr.get(spec.fsym, None) if val is None: mach.state.fail() else: if not mach.unify(val, spec): mach.state.fail() elif goal.fsym is PUT_ATTS: var = goal.args[0] spec = goal.args[1] assert isinstance(spec, Compound) mach.put_atts(var, spec.fsym, spec) elif goal.fsym is BIND_HARD: var = goal.args[0] val = goal.args[1] if isinstance(var, Variable) and var.instance is var: mach.bind_hard(var, val) else: if not mach.unify(var, val): mach.state.fail() elif goal.fsym is LIST_ATTS: var = goal.args[0] assert isinstance(var, Variable) ret = goal.args[1] res = Compound(NIL, []) for val in var.attr.itervalues(): res = Compound(CONS, [val, res]) if not mach.unify(ret, res): mach.state.fail() elif goal.fsym is DEF: head = goal.args[0] clause = goal.args[1] assert clause.fsym is CONS assert clause.args[0].fsym is CLAUSE top = mach.variant(clause.args[0]) nxt = clause.args[1] if nxt.fsym is not NIL: mach.state.choicepoint(mach, [Compound(DEF, [head, nxt])]) mach.state.expand([ Compound(UNIFY, [head, top.args[0]]), #Compound(WRITE, [head]), top.args[1] ]) elif goal.fsym in program.defs: clauses = program.defs[goal.fsym] mach.state.invoke(Compound(DEF, [goal, clauses])) elif goal.fsym in program.constraints: chr_add_constraint(goal, mach, program) elif goal.fsym is CHR_RESUME: chrid = goal.args[0] assert isinstance(chrid, Integer) chrid = chrid.bignum.toint() start = goal.args[1] assert isinstance(start, Integer) start = start.bignum.toint() chr_resume(chrid, start, mach, program) # Implementation of side effects in logic language # are bit of a question. # This looks like slightly wrong way to do it. elif goal.fsym is EXIT: a = goal.args[0].unroll() if is_ground(a): if isinstance(a, Integer): raise Exiting(a.bignum.toint()) else: mach.state.fail() elif mach.chr_lock: mach.state.fail() else: chr_add_constraint(goal, mach, program) elif goal.fsym is WRITE: a = goal.args[0].unroll() if is_ground(a): s = a.stringify() os.write(1, s + "\n") elif mach.chr_lock: mach.state.fail() else: chr_add_constraint(goal, mach, program) elif goal.fsym is CHR_REVISE: revise = goal a = goal.args[0] assert isinstance(a, Integer) i = a.bignum.toint() goal = mach.chr_by_id.get(i, None) if goal is not None: assert isinstance(goal, Compound) if goal.fsym is WRITE and is_ground(goal.args[0]): s = goal.args[0].stringify() os.write(1, s + "\n") elif goal.fsym is EXIT and is_ground(goal.args[0]): if isinstance(a, Integer): raise Exiting(a.bignum.toint()) else: mach.state.fail() else: deep_freeze(mach, goal, revise, True) chr_resume(i, 0, mach, program) elif goal.fsym is CHR_PRINTOUT: for chrid, const in mach.chr_by_id.iteritems(): s = const.stringify() os.write(1, "chr%d: %s\n" % (chrid, s)) else: raise ValueError("unknown predicate: %s" % goal.stringify()) if debug: print "=> " + mach.state.conj.stringify() goal = mach.state.next_goal(mach)
def clause_axiom(env, p): head = unbox(p[0]) body = Compound(env.getatom('true', 0), []) return Box(Compound(env.getatom('<-', 2), [head, body]))
def empty_guard(env, p): return Box(Compound(env.getatom('true', 0), []))
def goal_formula(env, p): a = unbox(p[0]) b = unbox(p[1]) return Box(Compound(env.getatom('and', 2), [a, b]))
def getcons(self, car, cdr): return Compound(self.getatom(":", 2), [car, cdr])
def getnil(self): return Compound(self.getatom("nil", 0), [])
def formula_unify(env, p): left = unbox(p[0]) right = unbox(p[2]) atom = env.getatom("=", 2) return Box(Compound(atom, [left, right]))
def predicate_compound(env, p): seq = as_list(unbox(p[2])) atom = env.getatom(p[0].getstr(), len(seq)) return Box(Compound(atom, seq))
def predicate_atom(env, p): return Box(Compound(env.getatom(p[0].getstr(), 0), []))
def clause_rule(env, p): head = unbox(p[0]) body = unbox(p[2]) return Box(Compound(env.getatom('<-', 2), [head, body]))