Token.java

package org.sterling.source.syntax;

import static org.sterling.source.syntax.NodeKind.UNDEFINED;

import java.util.Objects;
import org.sterling.source.LocationAware;
import org.sterling.source.LocationRange;

public class Token implements LocationAware {

    public static final Token NULL = token(UNDEFINED, "NULL", LocationRange.NULL);

    public static Token token(NodeKind kind, String value, LocationRange range) {
        return new Token(kind, value, range);
    }

    private final NodeKind kind;
    private final String value;
    private final LocationRange range;

    public Token(NodeKind kind, String value, LocationRange range) {
        if (!kind.isTerminal()) {
            throw new IllegalArgumentException("Token can only be non-terminal type");
        }
        this.kind = kind;
        this.value = value;
        this.range = range;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (o instanceof Token) {
            Token other = (Token) o;
            return kind == other.kind
                && Objects.equals(value, other.value)
                && Objects.equals(range, other.range);
        } else {
            return false;
        }
    }

    public NodeKind getKind() {
        return kind;
    }

    @Override
    public LocationRange getRange() {
        return range;
    }

    public String getValue() {
        return value;
    }

    @Override
    public int hashCode() {
        return Objects.hash(kind, value, range);
    }

    public boolean is(NodeKind kind) {
        return this.kind == kind;
    }

    @Override
    public String toString() {
        return kind + " '" + value.replace("\n", "\\n").replace("\0", "\\0") + "' [" + range + "]";
    }
}