From: qydysky Date: Thu, 21 Mar 2024 06:52:50 +0000 (+0800) Subject: 1 X-Git-Tag: v0.28.20240321065721 X-Git-Url: http://127.0.0.1:8081/?a=commitdiff_plain;h=c8573cb630d68a5d6a433c3f3f452d306804fa9b;p=part%2F.git 1 --- diff --git a/boolS/BoolS.go b/boolS/BoolS.go new file mode 100644 index 0000000..7015be3 --- /dev/null +++ b/boolS/BoolS.go @@ -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 index 0000000..1867548 --- /dev/null +++ b/boolS/BoolS_test.go @@ -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() + } +}