001package Torello.CSS;
002
003import Torello.Java.Additional.ByRef;
004
005import java.util.Vector;
006import java.util.function.Consumer;
007
008/** Any sequence of Whitespace */
009@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="CSS_TOK")
010public class Whitespace extends CSSToken
011    implements CharSequence, java.io.Serializable, Comparable<CharSequence>
012{
013    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
014    protected static final long serialVersionUID = 1;
015
016
017    // ********************************************************************************************
018    // ********************************************************************************************
019    // Private Constructor, API "is" and "if" Methods
020    // ********************************************************************************************
021    // ********************************************************************************************
022
023
024    private Whitespace(final int[] css, final int sPos, final int ePos)
025    { super(css, sPos, ePos); }
026
027    @Override 
028    public final boolean isWhitespace() { return true; }
029
030    @Override
031    public final Whitespace ifWhitespace() { return this; }
032
033
034    // ********************************************************************************************
035    // ********************************************************************************************
036    // Tokenizer's "is" Method(s)
037    // ********************************************************************************************
038    // ********************************************************************************************
039
040
041    // Currently this is Nearly Identical to what the CSSWG.org website says.  I am just not
042    // going to analyze \n\r today.  I truly have no way of testing this type of crap.
043    //
044    // Note that the JDK-21 JavaDoc has a rather lengthy list of what will make Java's
045    // java.lang.Character(int) is WhiteSpace return TRUE.
046    // 
047    // I will possibly change this to Character.isWhitespace(int codePoint) later...
048    // For Now - the Plan is to follow the "W3" ==> 
049    //      https://drafts.csswg.org/css-syntax/#whitespace
050
051    private static final char[] WHITE_SPACE_ARR =
052        { '\t', ' ', '\n', '\r', '\f', '\u000B' };
053
054    static boolean is(final int c)
055    {
056        for (char ws : WHITE_SPACE_ARR) if (c == ws) return true;
057        return false;
058    }
059
060
061    // ********************************************************************************************
062    // ********************************************************************************************
063    // User's Constructor: a static "build" method
064    // ********************************************************************************************
065    // ********************************************************************************************
066
067
068    /**
069     * <EMBED CLASS=defs DATA-TOK=Whitespace DATA-P=ws>
070     * <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_DESC>
071     * @param ws <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_PARAM>
072     * @return <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_RET>
073     * @throws TokenizeException <EMBED CLASS='external-html' DATA-FILE-ID=BUILD_TOK_EX>
074     */
075    @SuppressWarnings("unchecked")
076    public static Whitespace build(final String ws)
077    { return (Whitespace) CSSToken.build(ws, INPUT_CHECKER, Whitespace::consume); }
078
079    private static final CSSToken.InputChecker INPUT_CHECKER = (int[] css) ->
080    {
081        if (css.length == 0) throw new TokenizeException 
082            ("Input-String cannot have length 0.");
083
084        if (! is(css[0])) throw new TokenizeException
085            ("Input String does not start with a white-space character");
086    };
087
088
089    // ********************************************************************************************
090    // ********************************************************************************************
091    // CONSUME
092    // ********************************************************************************************
093    // ********************************************************************************************
094
095
096    /**
097     * This is a tokenizer method which <B>"consumes"</B> as much white-space as possible for the
098     * purpose of building a Whitespace Token.
099     * 
100     * <EMBED CLASS=defs DATA-TOK=Whitespace-Token DATA-URL=whitespace-token-diagram
101     *      DATA-OP=Consume>
102     * <EMBED CLASS=external-html DATA-FILE-ID=COPIED_CSS_WG_RR>
103     * <EMBED CLASS=external-html DATA-FILE-ID=WS_STAR_SVG>
104     * <EMBED CLASS=external-html DATA-FILE-ID=WHITESPACE_SVG>
105     * <EMBED CLASS=external-html DATA-FILE-ID=WHITESPACE_TOK_SVG>
106     */
107    protected static void consume(                          // When invoked from 'CSSTokenizer'
108            final int[]                 css,                // C, int[] css
109            final ByRef<Integer>        POS,                // P, array-pos loop-variable
110            final Consumer<CSSToken>    returnParsedToken   // T, Vector<CSSToken>.add
111        )
112    {
113        // NOTE: The algorithm will have already checked that css[0] is whitespace, or else it
114        //       would have not invoked this method in the first place.  This is what the CSS
115        //       Working Group Web-Site Pseudo-Code says, and this package "Sticks to the Plan"
116
117        int pos=(POS.f+1); // input-pos + 1 !!  Doesn't check the first character
118
119        TOP:
120        for (; pos < css.length; pos++)
121        {
122            int c = css[pos];
123            for (char ws : WHITE_SPACE_ARR) if (c == ws) continue TOP;
124            break TOP;
125        }
126
127        returnParsedToken.accept(new Whitespace(css, POS.f, pos));
128        POS.f = pos;
129    }
130}