package lexer import ( "gitea.paas.celticinfo.fr/oabrivard/gojson/token" ) type Lexer struct { input string position int readPosition int ch byte } func NewLexer(input string) *Lexer { l := &Lexer{input: input} l.readChar() return l } func (l *Lexer) NextToken() token.Token { var tok token.Token l.skipWhitespace() switch l.ch { case '{': tok = token.NewToken(token.BEGIN_OBJECT, l.ch) case '}': tok = token.NewToken(token.END_OBJECT, l.ch) case '[': tok = token.NewToken(token.BEGIN_ARRAY, l.ch) case ']': tok = token.NewToken(token.END_ARRAY, l.ch) case ':': tok = token.NewToken(token.NAME_SEPARATOR, l.ch) case ',': tok = token.NewToken(token.VALUE_SEPARATOR, l.ch) case '"': tok.Type = token.STRING tok.Value = l.readString() case 0: tok.Value = "" tok.Type = token.EOF default: if isDigit(l.ch) || l.ch == '-' { tok.Value = l.readNumber() tok.Type = token.NUMBER return tok } else if isLetter(l.ch) { tok.Value = l.readIdentifier() tok.Type = token.LookupIdent(tok.Value) return tok } else { tok = token.NewToken(token.ILLEGAL, l.ch) } } l.readChar() return tok } func (l *Lexer) readChar() { if l.readPosition >= len(l.input) { l.ch = 0 } else { l.ch = l.input[l.readPosition] } l.position = l.readPosition l.readPosition++ } func (l *Lexer) skipWhitespace() { for l.ch == ' ' || l.ch == '\t' || l.ch == '\n' || l.ch == '\r' { l.readChar() } } func (l *Lexer) readNumber() string { position := l.position for isDigit(l.ch) || l.ch == '.' || l.ch == '-' || l.ch == '+' || l.ch == 'e' || l.ch == 'E' { l.readChar() } return l.input[position:l.position] } func isDigit(ch byte) bool { return '0' <= ch && ch <= '9' } func (l *Lexer) readString() string { position := l.position + 1 for { l.readChar() if l.ch == '"' || l.ch == 0 { break } } return l.input[position:l.position] } func (l *Lexer) readIdentifier() string { position := l.position for isLetter(l.ch) { l.readChar() } return l.input[position:l.position] } func isLetter(ch byte) bool { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_' }