123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- package rdpar
- import "io"
- import "unicode"
- import "fmt"
- import "strings"
- import "strconv"
- type Kind int
- const (
- KindError Kind = -1
- KindNone Kind = 0
- KindBool Kind = iota + 1
- KindInt
- KindFloat
- KindWord
- KindString
- KindLast
- )
- type Value interface {
- // Kind() Kind
- }
- type Predicate func(c rune) bool
- type Converter func(s string) Value
- type Pos struct {
- Name *string
- Line int
- Col int
- }
- func (p Pos) String() string {
- name := "<stdin>"
- if p.Name != nil {
- name = *p.Name
- }
- return fmt.Sprintf("%s:%d:%d", name, p.Line, p.Col)
- }
- type State struct {
- Kind
- Token strings.Builder
- }
- type Parser struct {
- Pos
- Stack []State
- io.RuneScanner
- }
- func (p *Parser) WrapError(err error) Value {
- return (fmt.Errorf("%s:%w", p.Pos.String(), err))
- }
- func (p *Parser) Errorf(f string, args ...interface{}) Value {
- return p.WrapError(fmt.Errorf(f, args...))
- }
- func (p *Parser) Accept() string {
- res := p.Buffer().String()
- p.Pop()
- return res
- }
- func (p *Parser) ConvertFloat(s string) Value {
- f, err := strconv.ParseFloat(s, 64)
- if err != nil {
- return p.WrapError(err)
- }
- return float64(f)
- }
- func (p *Parser) ConvertInt(s string) Value {
- i, err := strconv.ParseInt(s, 0, 64)
- if err != nil {
- return p.WrapError(err)
- }
- return int64(i)
- }
- func (p *Parser) AcceptConvert(conv Converter) Value {
- return conv(p.Accept())
- }
- func (p Parser) State() Kind {
- return p.Stack[len(p.Stack)-1].Kind
- }
- func (p Parser) Buffer() *strings.Builder {
- return &(p.Stack[len(p.Stack)-1].Token)
- }
- func (p *Parser) Push(kind Kind) {
- s := State{Kind: kind}
- p.Stack = append(p.Stack, s)
- }
- func (p *Parser) Switch(kind Kind) {
- p.Stack[len(p.Stack)-1].Kind = kind
- }
- func (p *Parser) Pop() bool {
- if len(p.Stack) > 0 {
- p.Stack = p.Stack[0 : len(p.Stack)-1]
- return false
- }
- return true
- }
- func (p Parser) AppendToken(r rune) {
- p.Buffer().WriteRune(r)
- }
- func (p *Parser) Read() (r rune, ev Value) {
- r, _, err := p.ReadRune()
- if err != nil {
- return r, p.WrapError(err)
- }
- if r == '\n' {
- p.Line++
- p.Col = 0
- }
- p.Col++
- return r, nil
- }
- func (p *Parser) Unread() {
- // Do not bother to change pos here
- p.UnreadRune()
- }
- func (p *Parser) Peek() (r rune, ev Value) {
- r, err := p.Read()
- p.Unread()
- return r, err
- }
- func (p *Parser) ParseWord(end string) Value {
- c, err := p.Peek()
- if err != nil {
- return err
- }
- if !unicode.IsLetter(c) {
- return nil
- }
- p.Push(1)
- for {
- c, err = p.Read()
- if err != nil {
- return err
- }
- if strings.ContainsRune(end, c) {
- p.Unread()
- res := p.Accept()
- return string(res)
- } else {
- p.AppendToken(c)
- }
- }
- }
- func (p *Parser) Skip(in string) (err Value) {
- for {
- r, err := p.Read()
- if err != nil {
- return err
- }
- if !strings.ContainsRune(in, r) {
- p.Unread()
- return nil
- }
- }
- }
- func IsError(v Value) bool {
- if v == nil {
- return false
- }
- _, ok := v.(error)
- return ok
- }
- func (p *Parser) ParseNum(end string) Value {
- isFloat := false
- if ok := p.PeekIs(unicode.IsDigit); ok == nil || IsError(ok) {
- return ok
- }
- p.Push(KindInt)
- for {
- r, err := p.Read()
- if err != nil {
- return err
- }
- if strings.ContainsRune(end, r) {
- sval := p.Accept()
- if isFloat {
- fval, err := strconv.ParseFloat(sval, 64)
- if err != nil {
- return p.WrapError(err)
- }
- return float64(fval)
- } else {
- ival, err := strconv.ParseInt(sval, 0, 64)
- if err != nil {
- return p.WrapError(err)
- }
- return int64(ival)
- }
- } else if strings.ContainsRune("+-", r) {
- if p.Buffer().Len() > 0 {
- return p.Errorf("Sign only allowed at beginning of number")
- }
- p.AppendToken(r)
- } else if strings.ContainsRune("0123456789", r) {
- p.AppendToken(r)
- } else if r == '.' || r == 'e' {
- if isFloat {
- return p.Errorf("Incorrect floating point literal")
- }
- p.AppendToken(r)
- isFloat = true
- } else {
- return p.Errorf("Unexpected character in integer.")
- }
- }
- }
- func (p *Parser) PeekIs(pred func(rune) bool) (ok Value) {
- c, err := p.Peek()
- if err != nil {
- return err
- }
- if !pred(c) {
- return bool(false)
- }
- return bool(true)
- }
- func (p *Parser) PeekStart(start rune) (ok Value) {
- c, err := p.Peek()
- if err != nil {
- return err
- }
- if c != start {
- return bool(false)
- }
- return bool(true)
- }
- // uses the default \ escape
- func (p *Parser) ParseString(start, end rune) Value {
- escaped := false
- r, err := p.Peek()
- if err != nil {
- return err
- }
- if r != start {
- return nil
- }
- r, err = p.Read() // skip quote
- if err != nil {
- return err
- }
- p.Push(1)
- for {
- r, err = p.Read()
- if err != nil {
- return err
- }
- if r == '\\' {
- if escaped {
- p.AppendToken('\\')
- p.AppendToken('\\')
- escaped = false
- } else {
- escaped = true
- }
- } else if escaped {
- p.AppendToken('\\')
- p.AppendToken(r)
- escaped = false
- } else if r == end {
- sval := "\"" + p.Accept() + "\""
- str, err := strconv.Unquote(sval)
- if err != nil {
- return p.WrapError(err)
- }
- return string(str)
- } else {
- p.AppendToken(r)
- }
- }
- }
- // Raw string, only the end and the escape can be escaped
- func (p *Parser) ParseRawString(start, end, esc rune) Value {
- escaped := false
- r, err := p.Peek()
- if err != nil {
- return err
- }
- if r != start {
- return nil
- }
- r, err = p.Read() // skip quote
- if err != nil {
- return err
- }
- p.Push(1)
- for {
- r, err = p.Read()
- if err != nil {
- return err
- }
- if r == esc {
- if escaped {
- p.AppendToken(r)
- escaped = false
- } else {
- escaped = true
- }
- } else if r == end {
- if escaped {
- p.AppendToken(r)
- escaped = false
- } else {
- return p.Accept()
- }
- } else {
- p.AppendToken(r)
- }
- }
- }
|