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  }