ref 5
This commit is contained in:
parent
88c917210d
commit
e7584879a3
32
scanner.go
32
scanner.go
@ -7,6 +7,15 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Pre-declared errors to reduce allocations
|
||||
var (
|
||||
ErrUnterminatedString = errors.New("unterminated string")
|
||||
ErrUnterminatedEscape = errors.New("unterminated escape sequence")
|
||||
ErrUnterminatedComment = errors.New("unclosed block comment")
|
||||
ErrInvalidComment = errors.New("invalid comment")
|
||||
ErrNameStartWithLetter = errors.New("name must start with letter")
|
||||
)
|
||||
|
||||
// Scanner handles the low-level parsing of the configuration format
|
||||
type Scanner struct {
|
||||
reader *bufio.Reader
|
||||
@ -158,7 +167,7 @@ func (s *Scanner) NextToken() (Token, error) {
|
||||
// Just a single dash
|
||||
_, _ = s.ReadByte() // consume dash
|
||||
return Token{Type: TokenError, Value: []byte("unexpected '-'")},
|
||||
fmt.Errorf("unexpected '-' at line %d, column %d", startLine, startColumn)
|
||||
s.Error("unexpected '-'")
|
||||
|
||||
case b == '"':
|
||||
return s.scanString(startLine, startColumn)
|
||||
@ -171,8 +180,8 @@ func (s *Scanner) NextToken() (Token, error) {
|
||||
|
||||
default:
|
||||
_, _ = s.ReadByte() // consume the unexpected character
|
||||
err := fmt.Errorf("unexpected character: %c", b)
|
||||
return Token{Type: TokenError, Value: []byte(err.Error()), Line: startLine, Column: startColumn}, err
|
||||
return Token{Type: TokenError, Value: []byte(fmt.Sprintf("unexpected character: %c", b)), Line: startLine, Column: startColumn},
|
||||
s.Error(fmt.Sprintf("unexpected character: %c", b))
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +199,7 @@ func (s *Scanner) scanComment() error {
|
||||
return err
|
||||
}
|
||||
if b != '-' {
|
||||
return s.Error("invalid comment")
|
||||
return ErrInvalidComment
|
||||
}
|
||||
|
||||
// Check for block comment [[
|
||||
@ -202,7 +211,7 @@ func (s *Scanner) scanComment() error {
|
||||
for {
|
||||
b, err := s.ReadByte()
|
||||
if err != nil {
|
||||
return s.Error("unclosed block comment")
|
||||
return ErrUnterminatedComment
|
||||
}
|
||||
if b == ']' {
|
||||
if n, err := s.PeekByte(); err == nil && n == ']' {
|
||||
@ -243,7 +252,7 @@ func (s *Scanner) scanString(startLine, startColumn int) (Token, error) {
|
||||
for {
|
||||
b, err := s.ReadByte()
|
||||
if err != nil {
|
||||
return Token{Type: TokenError, Value: []byte("unterminated string")}, errors.New("unterminated string")
|
||||
return Token{Type: TokenError, Value: []byte(ErrUnterminatedString.Error())}, ErrUnterminatedString
|
||||
}
|
||||
|
||||
if b == '"' {
|
||||
@ -254,7 +263,7 @@ func (s *Scanner) scanString(startLine, startColumn int) (Token, error) {
|
||||
if b == '\\' {
|
||||
escaped, err := s.ReadByte()
|
||||
if err != nil {
|
||||
return Token{Type: TokenError, Value: []byte("unterminated escape sequence")}, errors.New("unterminated escape sequence")
|
||||
return Token{Type: TokenError, Value: []byte(ErrUnterminatedEscape.Error())}, ErrUnterminatedEscape
|
||||
}
|
||||
switch escaped {
|
||||
case '"':
|
||||
@ -273,7 +282,7 @@ func (s *Scanner) scanString(startLine, startColumn int) (Token, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Return token using buffer directly - we'll copy in NextToken if needed
|
||||
// Use the buffer directly - consumer is responsible for copying if needed
|
||||
return Token{
|
||||
Type: TokenString,
|
||||
Value: s.buffer,
|
||||
@ -294,7 +303,7 @@ func (s *Scanner) scanName(startLine, startColumn int) (Token, error) {
|
||||
}
|
||||
|
||||
if !isLetter(b) {
|
||||
return Token{Type: TokenError, Value: []byte("name must start with letter")}, s.Error("name must start with letter")
|
||||
return Token{Type: TokenError, Value: []byte(ErrNameStartWithLetter.Error())}, ErrNameStartWithLetter
|
||||
}
|
||||
s.buffer = append(s.buffer, b)
|
||||
|
||||
@ -314,10 +323,9 @@ func (s *Scanner) scanName(startLine, startColumn int) (Token, error) {
|
||||
_, _ = s.ReadByte()
|
||||
}
|
||||
|
||||
// Check if it's a boolean
|
||||
// Check if it's a boolean - fixed comparison
|
||||
tokenType := TokenName
|
||||
if len(s.buffer) == 4 && (s.buffer[0] == 't' && s.buffer[1] == 'r' && s.buffer[2] == 'u' && s.buffer[3] == 'e' ||
|
||||
s.buffer[0] == 'f' && s.buffer[1] == 'a' && s.buffer[2] == 'l' && s.buffer[3] == 's' && s.buffer[4] == 'e') {
|
||||
if string(s.buffer) == "true" || string(s.buffer) == "false" {
|
||||
tokenType = TokenBoolean
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user