2015-02-12 11:15:27 +00:00
|
|
|
package lexer
|
|
|
|
|
2015-02-16 08:54:53 +00:00
|
|
|
import "strings"
|
|
|
|
|
2015-02-12 11:15:27 +00:00
|
|
|
func lexInitial(l *Lexer) stateFn {
|
2015-02-16 08:54:53 +00:00
|
|
|
loop:
|
2015-02-12 11:15:27 +00:00
|
|
|
for {
|
2015-02-16 08:54:53 +00:00
|
|
|
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)
|
2015-02-12 11:15:27 +00:00
|
|
|
case EOF:
|
2015-02-16 08:54:53 +00:00
|
|
|
break loop
|
2015-02-12 11:15:27 +00:00
|
|
|
default:
|
2015-02-16 08:54:53 +00:00
|
|
|
panic("Unexpected symbol: " + string(r))
|
2015-02-12 11:15:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Correctly reached EOF.
|
|
|
|
l.emit(itemEOF)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-02-16 08:54:53 +00:00
|
|
|
// Skip all spaces
|
|
|
|
// One space has already been seen
|
|
|
|
func lexSpace(l *Lexer) stateFn {
|
|
|
|
for isSpace(l.peek()) {
|
|
|
|
l.next()
|
|
|
|
}
|
|
|
|
l.ignore()
|
2015-02-12 11:15:27 +00:00
|
|
|
return lexInitial
|
|
|
|
}
|
|
|
|
|
2015-02-16 08:54:53 +00:00
|
|
|
func lexNull(l *Lexer) stateFn {
|
|
|
|
if l.acceptString("null") {
|
|
|
|
l.emit(itemNull)
|
|
|
|
} else {
|
|
|
|
return l.errorf("Unexpected token")
|
|
|
|
}
|
2015-02-12 11:15:27 +00:00
|
|
|
return lexInitial
|
|
|
|
}
|
|
|
|
|
2015-02-16 08:54:53 +00:00
|
|
|
func lexBool(l *Lexer) stateFn {
|
|
|
|
if l.acceptString("true") || l.acceptString("false") {
|
|
|
|
l.emit(itemBool)
|
|
|
|
}
|
2015-02-12 11:15:27 +00:00
|
|
|
return lexInitial
|
|
|
|
}
|
|
|
|
|
2015-02-16 08:54:53 +00:00
|
|
|
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)
|
2015-02-12 11:15:27 +00:00
|
|
|
return lexInitial
|
|
|
|
}
|
|
|
|
|
2015-02-16 08:54:53 +00:00
|
|
|
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 EOF:
|
|
|
|
return l.errorf("String hits EOF")
|
|
|
|
default:
|
|
|
|
escaped = false
|
|
|
|
}
|
2015-02-12 11:15:27 +00:00
|
|
|
}
|
2015-02-16 08:54:53 +00:00
|
|
|
|
2015-02-12 11:15:27 +00:00
|
|
|
return lexInitial
|
|
|
|
}
|
2015-02-16 08:54:53 +00:00
|
|
|
|
|
|
|
func isSpace(r rune) bool {
|
|
|
|
return r == ' ' || r == '\t'
|
|
|
|
}
|
|
|
|
|
|
|
|
func isDigit(r rune) bool {
|
|
|
|
return strings.IndexRune("1234567890", r) > -1
|
|
|
|
}
|