github.com/jmigpin/editor@v1.6.0/util/parseutil/scanner.go (about)

     1  package parseutil
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strconv"
     7  	"unicode/utf8"
     8  )
     9  
    10  // not safe to parse concurrently (match/parse uses closures)
    11  type Scanner struct {
    12  	Src []byte
    13  	Pos int
    14  	M   ScMatch
    15  	P   ScParse
    16  
    17  	Reverse     bool // read direction
    18  	Debug       bool
    19  	ErrFilename string // used for errors only
    20  }
    21  
    22  func NewScanner() *Scanner {
    23  	sc := &Scanner{}
    24  	sc.M.init(sc)
    25  	sc.P.init(sc)
    26  	return sc
    27  }
    28  
    29  //----------
    30  
    31  func (sc *Scanner) SetSrc(src []byte) {
    32  	sc.Src = src
    33  	sc.Pos = 0
    34  }
    35  
    36  //----------
    37  
    38  func (sc *Scanner) ReadRune() (rune, error) {
    39  	ru := rune(0)
    40  	size := 0
    41  	if sc.Reverse {
    42  		ru, size = utf8.DecodeLastRune(sc.Src[:sc.Pos])
    43  		size = -size // decrease pos
    44  	} else {
    45  		ru, size = utf8.DecodeRune(sc.Src[sc.Pos:])
    46  	}
    47  	if size == 0 {
    48  		return 0, io.EOF
    49  	}
    50  	if sc.Debug {
    51  		fmt.Printf("%v: %q\n", sc.Pos, ru)
    52  	}
    53  	sc.Pos += size
    54  
    55  	return ru, nil
    56  }
    57  func (sc *Scanner) PeekRune() (rune, error) {
    58  	pos0 := sc.KeepPos()
    59  	ru, err := sc.ReadRune()
    60  	pos0.Restore()
    61  	return ru, err
    62  }
    63  
    64  //----------
    65  
    66  func (sc *Scanner) KeepPos() ScannerPos {
    67  	return ScannerPos{sc: sc, Pos: sc.Pos}
    68  }
    69  
    70  func (sc *Scanner) RestorePosOnErr(fn func() error) error {
    71  	pos0 := sc.KeepPos()
    72  	if err := fn(); err != nil {
    73  		pos0.Restore()
    74  		return err
    75  	}
    76  	return nil
    77  }
    78  
    79  //----------
    80  
    81  func (sc *Scanner) NewValueKeeper() *ScValueKeeper {
    82  	return &ScValueKeeper{sc: sc}
    83  }
    84  
    85  //----------
    86  
    87  func (sc *Scanner) SrcErrorf(f string, args ...any) error {
    88  	return sc.SrcError(fmt.Errorf(f, args...))
    89  }
    90  func (sc *Scanner) SrcError(err error) error {
    91  	return sc.SrcError2(err, 20)
    92  }
    93  func (sc *Scanner) SrcError2(err error, maxLen int) error {
    94  	filename := sc.ErrFilename
    95  	if filename == "" {
    96  		filename = "<bytes>"
    97  	}
    98  
    99  	// position
   100  	pos := sc.Pos
   101  	if pe, ok := err.(*ScPosError); ok {
   102  		pos = pe.Pos
   103  	}
   104  	if fe, ok := err.(*ScFatalError); ok {
   105  		pos = fe.Pos
   106  	}
   107  
   108  	line, col := IndexLineColumn2(sc.Src, pos)
   109  	str := SurroundingString(sc.Src, pos, maxLen)
   110  	return fmt.Errorf("%v:%d:%d: %v: %q", filename, line, col, err, str)
   111  }
   112  
   113  //----------
   114  //----------
   115  //----------
   116  
   117  type ScannerPos struct {
   118  	sc  *Scanner
   119  	Pos int
   120  }
   121  
   122  func (sp *ScannerPos) Restore() {
   123  	sp.sc.Pos = sp.Pos
   124  }
   125  func (sp *ScannerPos) IsEmpty() bool {
   126  	return sp.Pos == sp.sc.Pos
   127  }
   128  func (sp *ScannerPos) Len() int {
   129  	start, end := sp.StartEnd()
   130  	return end - start
   131  }
   132  func (sp *ScannerPos) StartEnd() (int, int) {
   133  	start, end := sp.Pos, sp.sc.Pos
   134  	if start > end { // support reverse mode
   135  		start, end = end, start
   136  	}
   137  	return start, end
   138  }
   139  func (sp *ScannerPos) Bytes() []byte {
   140  	start, end := sp.StartEnd()
   141  	return sp.sc.Src[start:end]
   142  }
   143  
   144  //----------
   145  //----------
   146  //----------
   147  
   148  // error with position
   149  type ScPosError struct {
   150  	Err error
   151  	Pos int
   152  }
   153  
   154  func (e *ScPosError) Error() string {
   155  	return e.Err.Error()
   156  }
   157  
   158  //----------
   159  
   160  type ScFatalError struct {
   161  	ScPosError
   162  }
   163  
   164  func IsScFatalError(err error) bool {
   165  	_, ok := err.(*ScFatalError)
   166  	return ok
   167  }
   168  
   169  //----------
   170  //----------
   171  //----------
   172  
   173  type ScValueKeeper struct {
   174  	sc    *Scanner
   175  	Value any
   176  }
   177  
   178  func (vk *ScValueKeeper) Reset() {
   179  	vk.Value = nil
   180  }
   181  
   182  //----------
   183  
   184  func (vk *ScValueKeeper) KeepBytes(fn ScFn) ScFn {
   185  	return func() error {
   186  		pos0 := vk.sc.KeepPos()
   187  		err := fn()
   188  		vk.Value = pos0.Bytes()
   189  		return err
   190  	}
   191  }
   192  func (vk *ScValueKeeper) KeepValue(fn ScValueFn) ScFn {
   193  	return func() error {
   194  		v, err := fn()
   195  		vk.Value = v
   196  		return err
   197  	}
   198  }
   199  
   200  //----------
   201  
   202  func (vk *ScValueKeeper) BytesOrNil() []byte {
   203  	if b, ok := vk.Value.([]byte); ok {
   204  		return b
   205  	}
   206  	return nil
   207  }
   208  
   209  //----------
   210  
   211  func (vk *ScValueKeeper) Int() (int, error) {
   212  	b, ok := vk.Value.([]byte)
   213  	if !ok {
   214  		return 0, fmt.Errorf("not []byte")
   215  	}
   216  	v, err := strconv.ParseInt(string(b), 10, 64)
   217  	if err != nil {
   218  		return 0, err
   219  	}
   220  	return int(v), nil
   221  }
   222  func (vk *ScValueKeeper) IntOrZero() int {
   223  	if v, err := vk.Int(); err == nil {
   224  		return v
   225  	}
   226  	return 0
   227  }
   228  
   229  //----------
   230  
   231  func (vk *ScValueKeeper) StringOptional() string {
   232  	if vk.Value == nil {
   233  		return ""
   234  	}
   235  	return vk.Value.(string)
   236  }
   237  func (vk *ScValueKeeper) String() string {
   238  	return vk.Value.(string)
   239  }
   240  
   241  //----------
   242  //----------
   243  //----------
   244  
   245  type ScFn func() error
   246  type ScValueFn func() (any, error)