github.com/jmigpin/editor@v1.6.0/util/parseutil/lrparser/ruleindex.go (about) 1 package lrparser 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // unique rule index 9 type RuleIndex struct { 10 m map[string]*Rule 11 pm map[string]ProcRuleFn 12 13 deref struct { 14 once bool 15 err error 16 } 17 } 18 19 func newRuleIndex() *RuleIndex { 20 ri := &RuleIndex{} 21 ri.m = map[string]*Rule{} 22 ri.pm = map[string]ProcRuleFn{} 23 return ri 24 } 25 26 //---------- 27 28 func (ri *RuleIndex) set(name string, r Rule) error { 29 if ri.deref.once { 30 return fmt.Errorf("calling set after dereference") 31 } 32 33 // need a level on indirection to have the ruleindex.map be iterable without issues when making rules unique. Forcing rules in the index to be of these types provides that (allowing directly a stringrule would cause issues). 34 switch r.(type) { 35 case *DefRule, *FuncRule, *BoolRule, *SingletonRule: 36 default: 37 return fmt.Errorf("unexpected type to set in ruleindex: %T", r) 38 } 39 40 // don't allow reserverd words to be names 41 switch name { 42 case "", "rule", "if": 43 return fmt.Errorf("bad rule name: %q", name) 44 } 45 46 if ri.has(name) { 47 return fmt.Errorf("rule already set: %v", name) 48 } 49 50 ri.m[name] = &r 51 return nil 52 } 53 func (ri *RuleIndex) has(name string) bool { 54 _, ok := ri.m[name] 55 return ok 56 } 57 func (ri *RuleIndex) get(name string) (Rule, bool) { 58 r, ok := ri.m[name] 59 if ok { 60 return *r, true 61 } 62 return nil, false 63 } 64 func (ri *RuleIndex) delete(name string) { 65 delete(ri.m, name) 66 } 67 68 //---------- 69 70 func (ri *RuleIndex) setDefRule(name string, r Rule) error { 71 r2 := &DefRule{name: name} 72 r2.setOnlyChild(r) 73 return ri.set(name, r2) 74 } 75 func (ri *RuleIndex) setBoolRule(name string, v bool) error { 76 r := &BoolRule{name: name, value: v} 77 return ri.set(name, r) 78 } 79 func (ri *RuleIndex) setFuncRule(name string, parseOrder int, fn PStateParseFn) error { 80 r := &FuncRule{name: name, parseOrder: parseOrder, fn: fn} 81 return ri.set(name, r) 82 } 83 func (ri *RuleIndex) setSingletonRule(r *SingletonRule) error { 84 return ri.set(r.name, r) 85 } 86 87 //---------- 88 89 func (ri *RuleIndex) setProcRuleFn(name string, fn ProcRuleFn) error { 90 if _, ok := ri.pm[name]; ok { 91 return fmt.Errorf("already defined: %v", name) 92 } 93 ri.pm[name] = fn 94 return nil 95 } 96 97 //---------- 98 99 func (ri *RuleIndex) derefRules() error { 100 if ri.deref.once { 101 return ri.deref.err 102 } 103 err := dereferenceRules(ri) 104 ri.deref.once = true 105 ri.deref.err = err 106 return err 107 } 108 109 //---------- 110 111 func (ri *RuleIndex) startRule(name string) (*DefRule, error) { 112 if r, ok := ri.m[name]; ok { 113 dr, ok := (*r).(*DefRule) 114 if !ok { 115 return nil, fmt.Errorf("not a defrule: %v", r) 116 } 117 dr.isStart = true 118 return dr, nil 119 } 120 // auto find marked rule 121 if name == "" { 122 res := (*DefRule)(nil) 123 for _, r := range ri.sorted() { 124 if dr, ok := r.(*DefRule); ok { 125 if dr.isStart { 126 if res != nil { 127 return nil, fmt.Errorf("no rule name given and more then one start rule defined") 128 } 129 res = dr 130 } 131 } 132 } 133 if res != nil { 134 return res, nil 135 } 136 } 137 return nil, fmt.Errorf("start rule not found: %q", name) 138 } 139 140 //---------- 141 142 //godebug:annotateoff 143 func (ri *RuleIndex) String() string { 144 res := []string{} 145 for _, r := range ri.sorted() { 146 if r.isTerminal() { // don't print terminals 147 continue 148 } 149 if dr, ok := r.(*DefRule); ok && dr.isNoPrint { 150 continue 151 } 152 res = append(res, fmt.Sprintf("%v", r)) 153 } 154 return fmt.Sprintf("ruleindex{\n\t%v\n}", strings.Join(res, "\n\t")) 155 } 156 157 func (ri *RuleIndex) sorted() []Rule { 158 w := []Rule{} 159 for _, r := range ri.m { 160 w = append(w, *r) 161 } 162 sortRules(w) 163 return w 164 }