// ->/2 func BuiltinIfThen(m Machine, args []term.Term) ForeignReturn { cond := args[0] then := args[1] // CUT_BARRIER, (cond, !, then) cut := term.NewCallable("!") goal := term.NewCallable(",", cond, term.NewCallable(",", cut, then)) return m.DemandCutBarrier().PushConj(goal) }
func ifThenElse(m Machine, args []term.Term) ForeignReturn { semicolon := args[0].(*term.Compound) cond := semicolon.Arguments()[0] then := semicolon.Arguments()[1] els := args[1] // CUT_BARRIER, (call(cond), !, then; else) cut := term.NewCallable("!") cond = term.NewCallable("call", cond) goal := term.NewCallable(",", cond, term.NewCallable(",", cut, then)) goal = term.NewCallable(";", goal, els) return m.DemandCutBarrier().PushConj(goal) }
// findall/3 func BuiltinFindall3(m Machine, args []term.Term) ForeignReturn { template := args[0] goal := args[1] // call(Goal), X=Template x := term.NewVar("_") call := term.NewCallable("call", goal) unify := term.NewCallable("=", x, template) prove := term.NewCallable(",", call, unify) proofs := m.ClearConjs().ClearDisjs().ProveAll(prove) // build a list from the results instances := make([]term.Term, 0) for _, proof := range proofs { t, err := proof.Resolve(x) MaybePanic(err) instances = append(instances, t) } return ForeignUnify(args[2], term.NewTermList(instances)) }
// call/* func BuiltinCall(m Machine, args []term.Term) ForeignReturn { // build a new goal with extra arguments attached bodyTerm := args[0].(term.Callable) functor := bodyTerm.Name() newArgs := make([]term.Term, 0) newArgs = append(newArgs, bodyTerm.Arguments()...) newArgs = append(newArgs, args[1:]...) goal := term.NewCallable(functor, newArgs...) // construct a machine that will prove this goal next return m.DemandCutBarrier().PushConj(goal) }
func (r *TermReader) restTerm(leftP, p priority, i *lex.List, o **lex.List, leftT term.Term, t *term.Term) bool { var op string var rightT term.Term var opP, lap, rap priority // fmt.Printf("seeking restTerm @ %d with %s\n", p, i.Value.Content) if r.infix(&op, &opP, &lap, &rap, i, o) && p >= opP && leftP <= lap && r.term(rap, *o, o, &rightT) { // fmt.Printf(" infix %s\n", op) t0 := term.NewCallable(op, leftT, rightT) return r.restTerm(opP, p, *o, o, t0, t) } if r.postfix(&op, &opP, &lap, i, o) && opP <= p && leftP <= lap { opT := term.NewCallable(op, leftT) return r.restTerm(opP, p, *o, o, opT, t) } // ε rule can always succeed // fmt.Printf(" invoking ε\n") *o = i *t = leftT return true }
// parse all list items after the first one func (r *TermReader) listItems(i *lex.List, o **lex.List, t *term.Term) bool { var arg, rest term.Term if r.tok(',', i, o) && r.term(999, *o, o, &arg) && r.listItems(*o, o, &rest) { *t = term.NewCallable(".", arg, rest) return true } if r.tok('|', i, o) && r.term(999, *o, o, &arg) && r.tok(']', *o, o) { *t = arg return true } if r.tok(']', i, o) { *t = term.NewAtom("[]") return true } return false }
// parse a single term func (r *TermReader) term(p priority, i *lex.List, o **lex.List, t *term.Term) bool { var op, f string var t0, t1 term.Term var opP, argP priority // fmt.Printf("seeking term with %s\n", i.Value.Content) // prefix operator if r.prefix(&op, &opP, &argP, i, o) && opP <= p && r.term(argP, *o, o, &t0) { opT := term.NewCallable(op, t0) return r.restTerm(opP, p, *o, o, opT, t) } // list notation for compound terms §6.3.5 if r.tok('[', i, o) && r.term(999, *o, o, &t0) && r.listItems(*o, o, &t1) { list := term.NewCallable(".", t0, t1) return r.restTerm(0, p, *o, o, list, t) } if r.tok('[', i, o) && r.tok(']', *o, o) { list := term.NewAtom("[]") return r.restTerm(0, p, *o, o, list, t) } // parenthesized terms if r.tok('(', i, o) && r.term(1200, *o, o, &t0) && r.tok(')', *o, o) { // fmt.Printf("open paren %s close paren\n", t0) return r.restTerm(0, p, *o, o, t0, t) } switch i.Value.Type { case lex.Int: // integer term §6.3.1.1 n := term.NewInt(i.Value.Content) *o = i.Next() return r.restTerm(0, p, *o, o, n, t) case lex.Float: // float term §6.3.1.1 f := term.NewFloat(i.Value.Content) *o = i.Next() return r.restTerm(0, p, *o, o, f, t) case lex.Atom: // atom term §6.3.1.3 a := term.NewAtomFromLexeme(i.Value.Content) *o = i.Next() return r.restTerm(0, p, *o, o, a, t) case lex.String: // double quated string §6.3.7 cl := term.NewCodeListFromDoubleQuotedString(i.Value.Content) *o = i.Next() return r.restTerm(0, p, *o, o, cl, t) case lex.Variable: // variable term §6.3.2 v := term.NewVar(i.Value.Content) *o = i.Next() return r.restTerm(0, p, *o, o, v, t) case lex.Void: // variable term §6.3.2 v := term.NewVar("_") *o = i.Next() return r.restTerm(0, p, *o, o, v, t) case lex.Comment: *o = i.Next() // skip the comment return r.term(p, *o, o, t) // ... and try again } // compound term - functional notation §6.3.3 if r.functor(i, o, &f) && r.tok('(', *o, o) { var args []term.Term var arg term.Term for r.term(999, *o, o, &arg) { // 999 priority per §6.3.3.1 args = append(args, arg) if r.tok(')', *o, o) { break } if r.tok(',', *o, o) { continue } panic("Unexpected content inside compound term arguments") } f := term.NewTermFromLexeme(f, args...) return r.restTerm(0, p, *o, o, f, t) } *t = term.NewError("Syntax error", i.Value) return false }