func (d *Dwimmer) Run(setting *term.SettingT) term.T { goMeta := func() { StartShell(d, Interrupted.T(represent.SettingT(setting))) } for { //d.watchdog(setting) char, sent := d.CheckCh() if sent { if char == 'q' { panic("interrupted") } else if char == 's' { goMeta() } else { d.Clear() d.Debug("(Type [s] to interrupt execution and drop into a shell)") d.Debug("(Type [q] to interrupt execution and quit)") } } transition, ok := d.Get(setting.Setting) if !ok { transition = ElicitAction(d, setting.Copy(), setting.Setting) } result := transition.Step(d, setting) if result != nil { return result } } }
func (d *Dwimmer) Answer(q term.T, optionalSetting ...*term.SettingT) (term.T, term.T) { var s *term.SettingT if len(optionalSetting) == 1 { s = optionalSetting[0] } else { s = term.InitT() s.AppendTerm(BuiltinAnswerer.T(q)) } a := dynamics.SubRun(d, q, s) switch a.Head() { case core.Answer: return a.Values()[0], nil case core.Yes, core.No: return a, nil } follow := term.InitT() isAnswer := dynamics.SubRun(d, IsAnswer.T(a, q), s, follow) for { switch isAnswer.Head() { case core.Yes: result, err := d.Answer(WhatAnswer.T(a, q)) if err != nil { return nil, a } return result, nil case core.No: return nil, a } isAnswer = dynamics.SubRun(d, IsAnswerClarify.T(), s, follow) } }
func getInput(d dynamics.Dwimmer, context *term.SettingT, hintstrings, toolmap term.T) term.T { quotedHints, err := represent.ToList(d, hintstrings) if err != nil { return represent.ConversionError.T(hintstrings, err) } hints := make([]string, len(quotedHints)) for i, quoted := range quotedHints { hints[i], err = represent.ToStr(d, quoted) if err != nil { return represent.ConversionError.T(quoted, err) } } tools := make(map[rune]string) for toolmap.Head() != maps.Empty { switch toolmap.Head() { case maps.Cons: vs := toolmap.Values() c, err := represent.ToRune(d, vs[0]) if err != nil { return represent.ConversionError.T(vs[0], err) } s, err := represent.ToStr(d, vs[1]) if err != nil { return represent.ConversionError.T(vs[1], err) } tools[c] = s toolmap = vs[2] default: context.AppendTerm(UnrecognizedDictionary.T()) return nil } } input := d.Readln(" < ", hints, tools) return core.Answer.T(represent.Str(input)) }
func (d *Dwimmer) watchdog(setting *term.SettingT) { if rand.Int()%(watchFrequency<<(3*watcherDepth)) == 0 { watcherDepth++ defer func() { watcherDepth-- }() parent := setting.Copy().AppendAction(term.MetaC()) oldWatcher := d.lastWatcher newWatcher := term.InitT() var Q term.T if d.lastWatcher == nil { Q = IsAllWell.T(term.MakeChannel(parent)) } else { Q = IsAllWellPred.T(term.MakeChannel(parent), term.MakeChannel(oldWatcher)) } d.lastWatcher = newWatcher dynamics.SubRun(d, Q, parent, newWatcher) } }
func SubRun(d Dwimmer, Q term.T, parent *term.SettingT, optionalChild ...*term.SettingT) term.T { var child *term.SettingT if len(optionalChild) == 1 { child = optionalChild[0] } else { child = term.InitT() } child.AppendTerm(Parent(parent)) child.AppendTerm(Q) d.Push(Q) stackCheck() A := d.Run(child) parent.AppendTerm(OpenChannel.T(term.MakeChannel(child))) if A != nil { parent.AppendTerm(A) } d.Pop() return A }
func parseInput(d dynamics.Dwimmer, context *term.SettingT, quotedInput, quotedNames term.T) term.T { input, err := represent.ToStr(d, quotedInput) if err != nil { return represent.ConversionError.T(quotedInput, err) } quotedList, err := represent.ToList(d, quotedNames) if err != nil { return represent.ConversionError.T(quotedNames, err) } names := make([]string, len(quotedList)) for i, quoted := range quotedList { names[i], err = represent.ToStr(d, quoted) if err != nil { return represent.ConversionError.T(quoted, err) } } if input == "jump up" { return GoMeta.T() } a := parsing.ParseAction(input, names) if a == nil { c := parsing.ParseTerm(input, names) if c != nil { switch c := c.(type) { case *term.CompoundC: if questionLike(c) { a = new(term.ActionC) *a = term.AskC(c) } case term.ReferenceC: a = new(term.ActionC) *a = term.ViewC(c) } context.AppendTerm(IsTerm.T()) return nil } else { context.AppendTerm(ParseError.T()) return nil } } else { for _, n := range a.IntArgs { if n < 0 { context.AppendTerm(ParseError.T()) return nil } } return core.Answer.T(represent.ActionC(*a)) } }
func (d *Dwimmer) Do(a term.ActionT, s *term.SettingT) term.T { switch a.Act { case term.Return: return a.Args[0] case term.Ask: Q := a.Args[0] child := term.InitT() dynamics.SubRun(d, Q, s, child) return nil case term.View: value := a.Args[0] if value != nil { s.AppendTerm(value) } else { s.AppendTerm(Closed.T()) } return nil case term.Replace: //value := a.Args[0] //n := a.IntArgs[0] //s.Rollback(n).AppendTerm(value) return nil case term.Replay: n := a.IntArgs[0] s.Rollback(n) return nil case term.Clarify: Q := a.Args[1] //TODO handle null pointers much better... //(e.g. one part of an expression may refer to a deleted variable) if a.Args[0] == nil { s.AppendTerm(Closed.T()) return nil } var target *term.SettingT channel, err := represent.ToChannel(d, a.Args[0]) if err == nil { target = channel.(term.Channel).Instantiate() } else { var othererr term.T target, othererr = represent.ToSettingT(d, a.Args[0]) if othererr != nil { s.AppendTerm(NotAChannel.T(err)) return nil } } dynamics.SubRun(d, Q, s, target) return nil case term.Correct: n := a.IntArgs[0] old := s.Setting.Rollback(n) transition := ElicitAction(d, term.InitT(), old) d.Save(old, transition) s.AppendTerm(core.OK.T()) return nil case term.Delete: n := a.IntArgs[0] s.Args[n] = nil s.AppendTerm(core.OK.T()) return nil case term.Meta: s.AppendTerm(CurrentSetting.T(represent.SettingT(s))) return nil } panic("unknown kind of action") }
func (t SimpleTransition) Step(d Dwimmer, s *term.SettingT) term.T { actC := t.Action s.AppendAction(actC) actT := actC.Instantiate(s.Args) return d.Do(actT, s) }