1
0
Fork 0
kifflom/lexer/state.go

129 lines
2.0 KiB
Go

package lexer
import "strings"
func lexInitial(l *Lexer) stateFn {
loop:
for {
switch r := l.next(); r {
case ' ', '\t':
return lexSpace(l)
case '\n':
l.lineNum++
case 'n':
l.backup()
return lexNull(l)
case 't', 'f':
l.backup()
return lexBool(l)
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0':
l.backup()
return lexNumber(l)
case '"':
return lexString(l)
case '[':
l.emit(itemBracketOpen)
case ']':
l.emit(itemBracketClose)
case '{':
l.emit(itemBraceOpen)
case '}':
l.emit(itemBraceClose)
case ':':
l.emit(itemColon)
case ',':
l.emit(itemComma)
case EOF:
break loop
default:
panic("Unexpected symbol: " + string(r))
}
}
// Correctly reached EOF.
l.emit(itemEOF)
return nil
}
// Skip all spaces
// One space has already been seen
func lexSpace(l *Lexer) stateFn {
for isSpace(l.peek()) {
l.next()
}
l.ignore()
return lexInitial
}
func lexNull(l *Lexer) stateFn {
if l.acceptString("null") {
l.emit(itemNull)
} else {
return l.errorf("Unexpected token")
}
return lexInitial
}
func lexBool(l *Lexer) stateFn {
if l.acceptString("true") || l.acceptString("false") {
l.emit(itemBool)
}
return lexInitial
}
func lexNumber(l *Lexer) stateFn {
hasDot := false
for {
if r := l.peek(); isDigit(r) {
l.next()
} else if r == '.' {
if hasDot {
return l.errorf("Invalid number")
} else {
hasDot = true
l.next()
}
} else {
break
}
}
l.emit(itemNumber)
return lexInitial
}
func lexString(l *Lexer) stateFn {
escaped := false
loop:
for {
switch r := l.next(); r {
case '\\':
escaped = true
case '"':
if escaped {
escaped = false
} else {
l.emit(itemString)
break loop
}
case '\n':
l.lineNum++
case EOF:
return l.errorf("String hits EOF")
default:
escaped = false
}
}
return lexInitial
}
func isSpace(r rune) bool {
return r == ' ' || r == '\t'
}
func isDigit(r rune) bool {
return strings.IndexRune("1234567890", r) > -1
}