]> 127.0.0.1 Git - part/.git/commitdiff
1 v0.28.20240321065721
authorqydysky <qydysky@foxmail.com>
Thu, 21 Mar 2024 06:52:50 +0000 (14:52 +0800)
committerqydysky <qydysky@foxmail.com>
Thu, 21 Mar 2024 06:52:50 +0000 (14:52 +0800)
boolS/BoolS.go [new file with mode: 0644]
boolS/BoolS_test.go [new file with mode: 0644]

diff --git a/boolS/BoolS.go b/boolS/BoolS.go
new file mode 100644 (file)
index 0000000..7015be3
--- /dev/null
@@ -0,0 +1,180 @@
+package bools
+
+import (
+       "errors"
+)
+
+type sr struct {
+       rule string
+       i    int
+       fin  bool
+       arg  map[string]func() bool
+}
+
+const (
+       emp = iota
+       and
+       or
+       not
+)
+
+var (
+       ErrNoAct      = errors.New("ErrNoAct")
+       ErrHadAct     = errors.New("ErrHadAct")
+       ErrUnkownChar = errors.New("ErrUnkownChar")
+)
+
+func New(s string, arg map[string]func() bool) *sr {
+       return &sr{s, 0, false, arg}
+}
+
+func (t *sr) SetRule(s string) *sr {
+       t.rule = s
+       t.i = 0
+       t.fin = t.i == len(t.rule)
+       return t
+}
+
+func (t *sr) SetArg(arg map[string]func() bool) *sr {
+       t.arg = arg
+       t.i = 0
+       t.fin = t.i == len(t.rule)
+       return t
+}
+
+func (t *sr) next() (b byte) {
+       b = t.rule[t.i]
+       t.i = t.i + 1
+       t.fin = t.i == len(t.rule)
+       return
+}
+
+func (t *sr) Check() (result bool, err error) {
+       result = true
+       act := and
+       no := emp
+       for !t.fin {
+               switch t.next() {
+               case '{':
+                       switch act {
+                       case and:
+                               if result {
+                                       if no == not {
+                                               result = result && !t.parseArg()
+                                       } else {
+                                               result = result && t.parseArg()
+                                       }
+                               } else {
+                                       t.skipTo('}')
+                                       return false, nil
+                               }
+                               no = emp
+                               act = emp
+                       case or:
+                               if result {
+                                       t.skipTo('}')
+                                       return true, nil
+                               } else {
+                                       if no == not {
+                                               result = result || !t.parseArg()
+                                       } else {
+                                               result = result || t.parseArg()
+                                       }
+                               }
+                               no = emp
+                               act = emp
+                       default:
+                               return false, ErrNoAct
+                       }
+               case '!':
+                       if no == emp {
+                               no = not
+                       } else {
+                               no = emp
+                       }
+               case '&':
+                       if act != emp || no != emp {
+                               return false, ErrHadAct
+                       }
+                       act = and
+               case '|':
+                       if act != emp || no != emp {
+                               return false, ErrHadAct
+                       }
+                       act = or
+               case '(':
+                       switch act {
+                       case and:
+                               if result {
+                                       if cr, e := t.Check(); e != nil {
+                                               return false, e
+                                       } else {
+                                               if no == not {
+                                                       result = result && !cr
+                                               } else {
+                                                       result = result && cr
+                                               }
+                                       }
+                               } else {
+                                       t.skipTo(')')
+                                       return false, nil
+                               }
+                               no = emp
+                               act = emp
+                       case or:
+                               if result {
+                                       t.skipTo(')')
+                                       return true, nil
+                               } else {
+                                       if cr, e := t.Check(); e != nil {
+                                               return false, e
+                                       } else {
+                                               if no == not {
+                                                       result = result || !cr
+                                               } else {
+                                                       result = result || cr
+                                               }
+                                       }
+                               }
+                               no = emp
+                               act = emp
+                       default:
+                               return false, ErrNoAct
+                       }
+               case ')':
+                       return
+               case '\t':
+               case '\n':
+               case ' ':
+               default:
+                       return false, ErrUnkownChar
+               }
+       }
+       return
+}
+
+func (t *sr) parseArg() bool {
+       cu := t.i
+       for !t.fin {
+               switch t.next() {
+               case '}':
+                       argB, ok := t.arg[t.rule[cu:t.i-1]]
+                       return argB() && ok
+               default:
+               }
+       }
+       return false
+}
+
+func (t *sr) skipTo(b byte) {
+       for !t.fin && t.next() != b {
+       }
+}
+
+func True() bool {
+       return true
+}
+
+func False() bool {
+       return false
+}
diff --git a/boolS/BoolS_test.go b/boolS/BoolS_test.go
new file mode 100644 (file)
index 0000000..1867548
--- /dev/null
@@ -0,0 +1,55 @@
+package bools
+
+import "testing"
+
+func TestMain(t *testing.T) {
+       s := New("{1}", map[string]func() bool{
+               "1": True,
+               "2": False,
+       })
+       if ok, e := s.SetRule("({2}&!{2})").Check(); e != nil || ok {
+               t.Fatal(e)
+       }
+       if ok, e := s.Check(); e != nil || !ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("!{1}").Check(); e != nil || ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("!!{1}").Check(); e != nil || !ok {
+               t.Fatal()
+       }
+       if _, e := s.SetRule("{1}{2}").Check(); e != ErrNoAct {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("{1}|{2}").Check(); e != nil || !ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("{1}&{2}").Check(); e != nil || ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("{1}&!{2}").Check(); e != nil || !ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("!{1}&!{2}&!{2}").Check(); e != nil || ok {
+               t.Fatal(e)
+       }
+       if ok, e := s.SetRule("!{1}&!{2}&!{2}").Check(); e != nil || ok {
+               t.Fatal(e)
+       }
+       if ok, e := s.SetRule("({1}&{2})").Check(); e != nil || ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("{1}&({1}&{2})").Check(); e != nil || ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("{1}&!({1}&{2})").Check(); e != nil || !ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("!{1}&({1}&!{2})").Check(); e != nil || ok {
+               t.Fatal()
+       }
+       if ok, e := s.SetRule("{2}&({1}&{1})").Check(); e != nil || ok {
+               t.Fatal()
+       }
+}