All Downloads are FREE. Search and download functionalities are using the official Maven repository.

us.bpsm.edn.Symbol Maven / Gradle / Ivy

// (c) 2012 B Smith-Mannschott -- Distributed under the Eclipse Public License
package us.bpsm.edn;

import static us.bpsm.edn.util.CharClassify.isDigit;
import static us.bpsm.edn.util.CharClassify.symbolStart;
import us.bpsm.edn.util.CharClassify;

import java.io.Serializable;

/**
 * A Symbol is {@linkplain Named}. Additionally it obeys the syntactic
 * restrictions defined for
 * edn Symbols.
 */
public final class Symbol implements Named, Comparable, Serializable {

    private final String prefix;
    private final String name;

    /**
     * {@inheritDoc}
     */
    public final String getPrefix() {
        return prefix;
    }

    /**
     * {@inheritDoc}
     */
    public final String getName() {
        return name;
    }

    private Symbol(String prefix, String name) {
        this.prefix = prefix.length() > 0 ? prefix : EMPTY;
        this.name = name;
    }

    /**
     * Provide a Symbol with the given prefix and name.
     * 
     * @param prefix
     *            An empty String or a non-empty String obeying the
     *            restrictions specified by edn. Never null.
     * @param name
     *            A non-empty string obeying the restrictions specified by edn.
     *            Never null.
     * @return a Symbol, never null.
     */
    public static Symbol newSymbol(String prefix, String name) {
        checkArguments(prefix, name);
        return new Symbol(prefix, name);
    }

    /**
     * Equivalent to {@code newSymbol("", name)}.
     * 
     * @param name
     *            A non-empty string obeying the restrictions specified by edn.
     *            Never null.
     * @return a Symbol with the given name and no prefix.
     */
    public static Symbol newSymbol(String name) {
        return newSymbol(EMPTY, name);
    }

    @Override
    public final int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + getClass().getName().hashCode();
        result = prime * result + name.hashCode();
        result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
        return result;
    }

    @Override
    public final boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Symbol other = (Symbol) obj;
        if (!name.equals(other.name)) {
            return false;
        }
        if (prefix == null) {
            if (other.prefix != null) {
                return false;
            }
        } else if (!prefix.equals(other.prefix)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        if (prefix.length() == 0) {
            return name;
        }
        return prefix + "/" + name;
    }

    private static void checkArguments(String prefix, String name) {
        if (prefix == null) {
            throw new EdnException("prefix must not be null.");
        }
        if (name == null) {
            throw new EdnException("name must not be null.");
        }
        checkName("name", name);
        if (prefix.length() != 0) {
            checkName("prefix", prefix);
        }
    }

    private static void checkName(String label, String ident) {
        if (ident.length() == 0) {
            throw new EdnSyntaxException("The " + label +
                                         " must not be empty.");
        }
        char first = ident.charAt(0);
        if (isDigit(first)) {
            throw new EdnSyntaxException("The " + label + " '" + ident
                    + "' must not begin with a digit.");
        }
        if (!symbolStart(first)) {
            throw new EdnSyntaxException("The " + label + " '" + ident
                    + "' begins with a forbidden character.");
        }
        if ((first == '.' || first == '-')
                && ident.length() > 1 && isDigit(ident.charAt(1))) {
            throw new EdnSyntaxException("The " + label + " '" + ident
                    + "' begins with a '-' or '.' followed by digit, "
                    + "which is forbidden.");
        }
        int n = ident.length();
        for (int i = 1; i < n; i++) {
            if (!CharClassify.symbolConstituent(ident.charAt(i))) {
                throw new EdnSyntaxException("The " + label + " '" + ident
                        + "' contains the illegal character '"
                        + ident.charAt(i) + "' at offset " + i + ".");
            }
        }
    }

    public int compareTo(Symbol right) {
        int cmp = prefix.compareTo(right.prefix);
        return cmp != 0 ? cmp : name.compareTo(right.name);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy