|
@@ -0,0 +1,148 @@
|
|
|
+package seq
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "log"
|
|
|
+ "reflect"
|
|
|
+)
|
|
|
+
|
|
|
+type SeqFunc func(s *Seq) error
|
|
|
+
|
|
|
+type Entry struct {
|
|
|
+ desc string
|
|
|
+ fn reflect.Value
|
|
|
+ seqFn SeqFunc
|
|
|
+ param []SeqParam
|
|
|
+ ret []reflect.Value
|
|
|
+ grab []reflect.Value
|
|
|
+}
|
|
|
+type SeqParam struct {
|
|
|
+ typ byte
|
|
|
+ nres int
|
|
|
+ ires int
|
|
|
+ // Or
|
|
|
+ param reflect.Value
|
|
|
+}
|
|
|
+
|
|
|
+func P(n, i int) SeqParam {
|
|
|
+ return SeqParam{1, n, i, reflect.Value{}}
|
|
|
+}
|
|
|
+func EP(n int) SeqParam {
|
|
|
+ return SeqParam{2, n, 0, reflect.Value{}}
|
|
|
+}
|
|
|
+
|
|
|
+type Seq struct {
|
|
|
+ seq []*Entry
|
|
|
+ last *Entry
|
|
|
+ vars map[string]interface{}
|
|
|
+
|
|
|
+ rep []string
|
|
|
+}
|
|
|
+
|
|
|
+func New() *Seq {
|
|
|
+ return &Seq{[]*Entry{}, nil, map[string]interface{}{}, nil}
|
|
|
+}
|
|
|
+
|
|
|
+func (s *Seq) Add(params ...interface{}) *Seq {
|
|
|
+ entry := &Entry{}
|
|
|
+ fni := 0
|
|
|
+ if v, ok := params[0].(string); ok {
|
|
|
+ entry.desc = v
|
|
|
+ fni = 1
|
|
|
+ }
|
|
|
+ fn := params[fni]
|
|
|
+
|
|
|
+ if v, ok := fn.(SeqFunc); ok {
|
|
|
+ entry.seqFn = v
|
|
|
+ } else {
|
|
|
+ entry.fn = reflect.ValueOf(fn)
|
|
|
+ fnTyp := reflect.TypeOf(fn)
|
|
|
+
|
|
|
+ if fnTyp.Kind() != reflect.Func {
|
|
|
+ log.Fatal("First param must be a function")
|
|
|
+ }
|
|
|
+ vparam := []SeqParam{}
|
|
|
+
|
|
|
+ for _, p := range params[fni+1:] {
|
|
|
+ sp := SeqParam{}
|
|
|
+ switch v := p.(type) {
|
|
|
+ case SeqParam:
|
|
|
+ sp = v
|
|
|
+ default:
|
|
|
+ sp.typ = 0
|
|
|
+ sp.param = reflect.ValueOf(p)
|
|
|
+ }
|
|
|
+ vparam = append(vparam, sp)
|
|
|
+ }
|
|
|
+ entry.param = vparam
|
|
|
+ }
|
|
|
+
|
|
|
+ s.seq = append(s.seq, entry)
|
|
|
+ s.last = entry
|
|
|
+ return s
|
|
|
+}
|
|
|
+
|
|
|
+func (s *Seq) Grab(grab ...interface{}) {
|
|
|
+ if s.last == nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for _, g := range grab {
|
|
|
+ gv := reflect.ValueOf(g)
|
|
|
+ if gv.Kind() != reflect.Ptr {
|
|
|
+ panic("Grab should be pointer")
|
|
|
+ }
|
|
|
+ s.last.grab = append(s.last.grab, gv)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (s *Seq) Log(param...interface{){
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+func (s *Seq) Exec(eparam ...interface{}) error {
|
|
|
+ s.rep = []string{}
|
|
|
+ for _, e := range s.seq {
|
|
|
+
|
|
|
+ if e.seqFn != nil {
|
|
|
+ err := e.seqFn(s)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ param := []reflect.Value{}
|
|
|
+ for _, p := range e.param {
|
|
|
+ var val reflect.Value
|
|
|
+ switch p.typ {
|
|
|
+ case 0:
|
|
|
+ val = p.param
|
|
|
+ case 1:
|
|
|
+ val = s.seq[p.nres].ret[p.ires]
|
|
|
+ case 2:
|
|
|
+ val = reflect.Indirect(reflect.ValueOf(eparam[p.nres]))
|
|
|
+ }
|
|
|
+ param = append(param, val)
|
|
|
+ }
|
|
|
+ e.ret = e.fn.Call(param)
|
|
|
+ for i, r := range e.ret { // Populate grabs
|
|
|
+ if i < len(e.grab) {
|
|
|
+ e.grab[i].Elem().Set(r)
|
|
|
+ }
|
|
|
+ if err, ok := r.Interface().(error); ok {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if e.desc != "" { // Only if we have a description
|
|
|
+ iret := []interface{}{}
|
|
|
+ for _, r := range e.ret {
|
|
|
+ iret = append(iret, reflect.Indirect(r).Interface())
|
|
|
+ }
|
|
|
+ s.rep = append(s.rep, fmt.Sprintf("E: %s => %s", e.desc, iret))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.Println("Report:")
|
|
|
+ for _, r := range s.rep {
|
|
|
+ log.Println(r)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|