gitlab.com/apertussolutions/u-root@v7.0.0+incompatible/cmds/core/elvish/parse/parser.go (about)

     1  package parse
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"unicode/utf8"
     9  
    10  	"github.com/u-root/u-root/cmds/core/elvish/util"
    11  )
    12  
    13  // Parser maintains some mutable states of parsing.
    14  //
    15  // NOTE: The str member is assumed to be valid UF-8.
    16  type Parser struct {
    17  	srcName string
    18  	src     string
    19  	pos     int
    20  	overEOF int
    21  	cutsets []map[rune]int
    22  	errors  Error
    23  }
    24  
    25  // NewParser creates a new parser from a piece of source text and its name.
    26  func NewParser(srcname, src string) *Parser {
    27  	return &Parser{srcname, src, 0, 0, []map[rune]int{{}}, Error{}}
    28  }
    29  
    30  // Done tells the parser that parsing has completed.
    31  func (ps *Parser) Done() {
    32  	if ps.pos != len(ps.src) {
    33  		r, _ := utf8.DecodeRuneInString(ps.src[ps.pos:])
    34  		ps.error(fmt.Errorf("unexpected rune %q", r))
    35  	}
    36  }
    37  
    38  // Errors gets the parsing errors after calling one of the parse* functions. If
    39  // the return value is not nil, it is always of type Error.
    40  func (ps *Parser) Errors() error {
    41  	if len(ps.errors.Entries) > 0 {
    42  		return &ps.errors
    43  	}
    44  	return nil
    45  }
    46  
    47  // Source returns the source code that is being parsed.
    48  func (ps *Parser) Source() string {
    49  	return ps.src
    50  }
    51  
    52  const eof rune = -1
    53  
    54  func (ps *Parser) peek() rune {
    55  	if ps.pos == len(ps.src) {
    56  		return eof
    57  	}
    58  	r, _ := utf8.DecodeRuneInString(ps.src[ps.pos:])
    59  	return r
    60  }
    61  
    62  func (ps *Parser) hasPrefix(prefix string) bool {
    63  	return strings.HasPrefix(ps.src[ps.pos:], prefix)
    64  }
    65  
    66  func (ps *Parser) next() rune {
    67  	if ps.pos == len(ps.src) {
    68  		ps.overEOF++
    69  		return eof
    70  	}
    71  	r, s := utf8.DecodeRuneInString(ps.src[ps.pos:])
    72  	ps.pos += s
    73  	return r
    74  }
    75  
    76  func (ps *Parser) backup() {
    77  	if ps.overEOF > 0 {
    78  		ps.overEOF--
    79  		return
    80  	}
    81  	_, s := utf8.DecodeLastRuneInString(ps.src[:ps.pos])
    82  	ps.pos -= s
    83  }
    84  
    85  func (ps *Parser) errorp(begin, end int, e error) {
    86  	ps.errors.Add(e.Error(), util.NewSourceRange(ps.srcName, ps.src, begin, end))
    87  }
    88  
    89  func (ps *Parser) error(e error) {
    90  	end := ps.pos
    91  	if end < len(ps.src) {
    92  		end++
    93  	}
    94  	ps.errorp(ps.pos, end, e)
    95  }
    96  
    97  func newError(text string, shouldbe ...string) error {
    98  	if len(shouldbe) == 0 {
    99  		return errors.New(text)
   100  	}
   101  	var buf bytes.Buffer
   102  	if len(text) > 0 {
   103  		buf.WriteString(text + ", ")
   104  	}
   105  	buf.WriteString("should be " + shouldbe[0])
   106  	for i, opt := range shouldbe[1:] {
   107  		if i == len(shouldbe)-2 {
   108  			buf.WriteString(" or ")
   109  		} else {
   110  			buf.WriteString(", ")
   111  		}
   112  		buf.WriteString(opt)
   113  	}
   114  	return errors.New(buf.String())
   115  }