package text
import (
)
type Decoder struct {
lastCall call
lastToken Token
lastErr error
openStack []byte
orig []byte
in []byte
}
func ( []byte) *Decoder {
return &Decoder{orig: , in: }
}
var ErrUnexpectedEOF = errors.New("%v", io.ErrUnexpectedEOF)
type call uint8
const (
readCall call = iota
peekCall
)
func ( *Decoder) () (Token, error) {
defer func() { .lastCall = peekCall }()
if .lastCall == readCall {
.lastToken, .lastErr = .Read()
}
return .lastToken, .lastErr
}
func ( *Decoder) () (Token, error) {
defer func() { .lastCall = readCall }()
if .lastCall == peekCall {
return .lastToken, .lastErr
}
, := .parseNext(.lastToken.kind)
if != nil {
return Token{},
}
switch .kind {
case comma, semicolon:
, = .parseNext(.kind)
if != nil {
return Token{},
}
}
.lastToken =
return , nil
}
const (
mismatchedFmt = "mismatched close character %q"
unexpectedFmt = "unexpected character %q"
)
func ( *Decoder) ( Kind) (Token, error) {
.consume(0)
:= false
if len(.in) == 0 {
= true
}
switch {
case EOF:
return .consumeToken(EOF, 0, 0), nil
case bof:
if {
return .consumeToken(EOF, 0, 0), nil
}
return .parseFieldName()
case Name:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case '{', '<':
.pushOpenStack()
return .consumeToken(MessageOpen, 1, 0), nil
case '[':
.pushOpenStack()
return .consumeToken(ListOpen, 1, 0), nil
default:
return .parseScalar()
}
case Scalar:
, := .currentOpenKind()
switch {
case bof:
if {
return .consumeToken(EOF, 0, 0), nil
}
switch .in[0] {
case ',':
return .consumeToken(comma, 1, 0), nil
case ';':
return .consumeToken(semicolon, 1, 0), nil
default:
return .parseFieldName()
}
case MessageOpen:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case :
.popOpenStack()
return .consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[]:
return Token{}, .newSyntaxError(mismatchedFmt, )
case ',':
return .consumeToken(comma, 1, 0), nil
case ';':
return .consumeToken(semicolon, 1, 0), nil
default:
return .parseFieldName()
}
case ListOpen:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case ']':
.popOpenStack()
return .consumeToken(ListClose, 1, 0), nil
case ',':
return .consumeToken(comma, 1, 0), nil
default:
return Token{}, .newSyntaxError(unexpectedFmt, )
}
}
case MessageOpen:
if {
return Token{}, ErrUnexpectedEOF
}
, := .currentOpenKind()
switch := .in[0]; {
case :
.popOpenStack()
return .consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[]:
return Token{}, .newSyntaxError(mismatchedFmt, )
default:
return .parseFieldName()
}
case MessageClose:
, := .currentOpenKind()
switch {
case bof:
if {
return .consumeToken(EOF, 0, 0), nil
}
switch := .in[0]; {
case ',':
return .consumeToken(comma, 1, 0), nil
case ';':
return .consumeToken(semicolon, 1, 0), nil
default:
return .parseFieldName()
}
case MessageOpen:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case :
.popOpenStack()
return .consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[]:
return Token{}, .newSyntaxError(mismatchedFmt, )
case ',':
return .consumeToken(comma, 1, 0), nil
case ';':
return .consumeToken(semicolon, 1, 0), nil
default:
return .parseFieldName()
}
case ListOpen:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case :
.popOpenStack()
return .consumeToken(ListClose, 1, 0), nil
case ',':
return .consumeToken(comma, 1, 0), nil
default:
return Token{}, .newSyntaxError(unexpectedFmt, )
}
}
case ListOpen:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case ']':
.popOpenStack()
return .consumeToken(ListClose, 1, 0), nil
case '{', '<':
.pushOpenStack()
return .consumeToken(MessageOpen, 1, 0), nil
default:
return .parseScalar()
}
case ListClose:
, := .currentOpenKind()
switch {
case bof:
if {
return .consumeToken(EOF, 0, 0), nil
}
switch := .in[0]; {
case ',':
return .consumeToken(comma, 1, 0), nil
case ';':
return .consumeToken(semicolon, 1, 0), nil
default:
return .parseFieldName()
}
case MessageOpen:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case :
.popOpenStack()
return .consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[]:
return Token{}, .newSyntaxError(mismatchedFmt, )
case ',':
return .consumeToken(comma, 1, 0), nil
case ';':
return .consumeToken(semicolon, 1, 0), nil
default:
return .parseFieldName()
}
default:
}
case comma, semicolon:
, := .currentOpenKind()
switch {
case bof:
if {
return .consumeToken(EOF, 0, 0), nil
}
return .parseFieldName()
case MessageOpen:
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case :
.popOpenStack()
return .consumeToken(MessageClose, 1, 0), nil
case otherCloseChar[]:
return Token{}, .newSyntaxError(mismatchedFmt, )
default:
return .parseFieldName()
}
case ListOpen:
if == semicolon {
break
}
if {
return Token{}, ErrUnexpectedEOF
}
switch := .in[0]; {
case '{', '<':
.pushOpenStack()
return .consumeToken(MessageOpen, 1, 0), nil
default:
return .parseScalar()
}
}
}
, := .Position(len(.orig) - len(.in))
panic(fmt.Sprintf("Decoder.parseNext: bug at handling line %d:%d with lastKind=%v", , , ))
}
var otherCloseChar = map[byte]byte{
'}': '>',
'>': '}',
}
func ( *Decoder) () (Kind, byte) {
if len(.openStack) == 0 {
return bof, 0
}
:= .openStack[len(.openStack)-1]
switch {
case '{':
return MessageOpen, '}'
case '<':
return MessageOpen, '>'
case '[':
return ListOpen, ']'
}
panic(fmt.Sprintf("Decoder: openStack contains invalid byte %c", ))
}
func ( *Decoder) ( byte) {
.openStack = append(.openStack, )
}
func ( *Decoder) () {
.openStack = .openStack[:len(.openStack)-1]
}
func ( *Decoder) () ( Token, error) {
defer func() {
if == nil && .tryConsumeChar(':') {
.attrs |= hasSeparator
}
}()
if .in[0] == '[' {
return .parseTypeName()
}
if := parseIdent(.in, false); > 0 {
return .consumeToken(Name, , uint8(IdentName)), nil
}
if := parseNumber(.in); .size > 0 {
if !.neg && .kind == numDec {
if , := strconv.ParseInt(string(.in[:.size]), 10, 32); == nil {
return .consumeToken(Name, .size, uint8(FieldNumber)), nil
}
}
return Token{}, .newSyntaxError("invalid field number: %s", .in[:.size])
}
return Token{}, .newSyntaxError("invalid field name: %s", errId(.in))
}
func ( *Decoder) () (Token, error) {
:= len(.orig) - len(.in)
:= consume(.in[1:], 0)
if len() == 0 {
return Token{}, ErrUnexpectedEOF
}
var []byte
for len() > 0 && isTypeNameChar([0]) {
= append(, [0])
= [1:]
}
= consume(, 0)
var bool
for len() > 0 && ! {
switch {
case [0] == ']':
= [1:]
= true
case [0] == '/', [0] == '.':
if len() > 0 && ([len()-1] == '/' || [len()-1] == '.') {
return Token{}, .newSyntaxError("invalid type URL/extension field name: %s",
.orig[:len(.orig)-len()+1])
}
= append(, [0])
= [1:]
= consume(, 0)
for len() > 0 && isTypeNameChar([0]) {
= append(, [0])
= [1:]
}
= consume(, 0)
default:
return Token{}, .newSyntaxError(
"invalid type URL/extension field name: %s", .orig[:len(.orig)-len()+1])
}
}
if ! {
return Token{}, ErrUnexpectedEOF
}
:= len()
if == 0 || [0] == '.' || [-1] == '.' || [-1] == '/' {
return Token{}, .newSyntaxError("invalid type URL/extension field name: %s",
.orig[:len(.orig)-len()])
}
.in =
:= len(.orig) - len(.in)
.consume(0)
return Token{
kind: Name,
attrs: uint8(TypeName),
pos: ,
raw: .orig[:],
str: string(),
}, nil
}
func ( byte) bool {
return ( == '-' || == '_' ||
('0' <= && <= '9') ||
('a' <= && <= 'z') ||
('A' <= && <= 'Z'))
}
func ( byte) bool {
switch {
case ' ', '\n', '\r', '\t':
return true
default:
return false
}
}
func ( []byte, bool) int {
var int
:=
if len() == 0 {
return 0
}
if && [0] == '-' {
= [1:]
++
if len() == 0 {
return 0
}
}
switch {
case [0] == '_',
'a' <= [0] && [0] <= 'z',
'A' <= [0] && [0] <= 'Z':
= [1:]
++
default:
return 0
}
for len() > 0 && ([0] == '_' ||
'a' <= [0] && [0] <= 'z' ||
'A' <= [0] && [0] <= 'Z' ||
'0' <= [0] && [0] <= '9') {
= [1:]
++
}
if len() > 0 && !isDelim([0]) {
return 0
}
return
}
func ( *Decoder) () (Token, error) {
if .in[0] == '"' || .in[0] == '\'' {
return .parseStringValue()
}
if , := .parseLiteralValue(); {
return , nil
}
if , := .parseNumberValue(); {
return , nil
}
return Token{}, .newSyntaxError("invalid scalar value: %s", errId(.in))
}
func ( *Decoder) () (Token, bool) {
:= parseIdent(.in, true)
if == 0 {
return Token{}, false
}
return .consumeToken(Scalar, , literalValue), true
}
func ( *Decoder) ( Kind, int, uint8) Token {
:= Token{
kind: ,
attrs: ,
pos: len(.orig) - len(.in),
raw: .in[:],
}
.consume()
return
}
func ( *Decoder) ( string, ...interface{}) error {
:= errors.New(, ...)
, := .Position(len(.orig) - len(.in))
return errors.New("syntax error (line %d:%d): %v", , , )
}
func ( *Decoder) ( int) ( int, int) {
:= .orig[:]
= bytes.Count(, []byte("\n")) + 1
if := bytes.LastIndexByte(, '\n'); >= 0 {
= [+1:]
}
= utf8.RuneCount() + 1
return ,
}
func ( *Decoder) ( byte) bool {
if len(.in) > 0 && .in[0] == {
.consume(1)
return true
}
return false
}
func ( *Decoder) ( int) {
.in = consume(.in, )
return
}
func ( []byte, int) []byte {
= [:]
for len() > 0 {
switch [0] {
case ' ', '\n', '\r', '\t':
= [1:]
case '#':
if := bytes.IndexByte(, '\n'); >= 0 {
= [+len("\n"):]
} else {
= nil
}
default:
return
}
}
return
}
func ( []byte) []byte {
const = 32
for := 0; < len(); {
if > {
return append([::], "…"...)
}
, := utf8.DecodeRune([:])
if > utf8.RuneSelf || ( != '/' && isDelim(byte())) {
if == 0 {
=
}
return [::]
}
+=
}
return
}
func ( byte) bool {
return !( == '-' || == '+' || == '.' || == '_' ||
('a' <= && <= 'z') ||
('A' <= && <= 'Z') ||
('0' <= && <= '9'))
}