GQLTokenizer.java

package net.morimekta.providence.graphql.parser;

import net.morimekta.util.lexer.TokenizerBase;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.Reader;

public class GQLTokenizer extends TokenizerBase<GQLTokenType, GQLToken> {
    public GQLTokenizer(Reader in) {
        super(in, TokenizerBase.DEFAULT_BUFFER_SIZE, true);
    }

    @Override
    protected GQLToken genericToken(char[] buffer, int offset, int len,
                                    @Nonnull GQLTokenType type, int lineNo, int linePos) {
        return new GQLToken(buffer, offset, len, type, lineNo, linePos);
    }

    @Override
    protected GQLToken identifierToken(char[] buffer, int offset, int len, int lineNo, int linePos) {
        GQLTokenType type = GQLTokenType.IDENTIFIER;
        if (buffer[offset] == GQLToken.kDirective) type = GQLTokenType.DIRECTIVE;
        else if (buffer[offset] == GQLToken.kVariable) type = GQLTokenType.VARIABLE;
        return new GQLToken(buffer, offset, len, type, lineNo, linePos);
    }

    @Override
    protected GQLToken stringToken(char[] buffer, int offset, int len, int lineNo, int linePos) {
        return new GQLToken(buffer, offset, len, GQLTokenType.STRING, lineNo, linePos);
    }

    @Override
    protected GQLToken numberToken(char[] buffer, int offset, int len, int lineNo, int linePos) {
        GQLTokenType type = GQLTokenType.INTEGER;
        for (int i = offset; i < offset + len; ++i) {
            if (buffer[i] == '.' || buffer[i] == 'e' || buffer[i] == 'E') {
                type = GQLTokenType.FLOAT;
                break;
            }
        }
        return new GQLToken(buffer, offset, len, type, lineNo, linePos);
    }

    @Override
    protected GQLToken symbolToken(char[] buffer, int offset, int len, int lineNo, int linePos) {
        return new GQLToken(buffer, offset, len, GQLTokenType.SYMBOL, lineNo, linePos);
    }

    @Override
    protected boolean startNumber() {
        return lastChar != '.' && super.startNumber();
    }

    @Override
    protected boolean startIdentifier() {
        return lastChar == GQLToken.kVariable ||
               lastChar == GQLToken.kDirective ||
               super.startIdentifier();
    }

    @Override
    protected boolean allowIdentifier(int last) {
        return last != '.' && super.allowIdentifier(last);
    }

    @Override
    protected boolean identifierSeparator(int last) {
        return last == GQLToken.kVariable ||
               last == GQLToken.kDirective ;
    }

    @Nonnull
    @Override
    protected GQLToken nextSymbol() throws IOException {
        if (lastChar == '.') {
            int startOffset = bufferOffset;
            int startLinePos = linePos;
            int startLineNo = lineNo;

            GQLToken fail;
            readNextChar();
            if (lastChar == '.') {
                readNextChar();
                if (lastChar == '.') {
                    lastChar = 0;
                    return genericToken(buffer, startOffset, 3, GQLTokenType.SYMBOL, startLineNo, startLinePos);
                }

                fail = genericToken(buffer, startOffset, 3, GQLTokenType.SYMBOL, startLineNo, startLinePos);
            } else {
                fail = genericToken(buffer, startOffset, 2, GQLTokenType.SYMBOL, startLineNo, startLinePos);
            }
            throw failure(fail, "Invalid spread specialization: '%s'", fail.toString());
        }
        return super.nextSymbol();
    }
}